{"openapi":"3.1.0","info":{"title":"Sceniq creator API","version":"2026-09-30.2","description":"Build and edit Sceniq travel guides as the creator's assistant. Every operation except the two photo uploads is also an MCP tool at /mcp with the same name and input. A key with the publish option can publish a live guide's changes (publish_changes, x-scope publish) when the creator asks; putting a draft on sale and store visibility stay in the studio. Docs: https://sceniq.earth/developers","x-authoring-guide-version":"2026-09-30.3"},"servers":[{"url":"https://sceniq.earth/api/v1"}],"security":[{"bearerAuth":[]}],"tags":[{"name":"account","description":"Account"},{"name":"guides","description":"Guides"},{"name":"properties","description":"Custom properties"},{"name":"spots","description":"Spots"},{"name":"areas","description":"Areas: parks, islands, regions"},{"name":"chapters","description":"Chapters and collections"},{"name":"routes","description":"Routes (how to get there)"},{"name":"facilities","description":"Places: stays, transport, food, parking"},{"name":"media","description":"Photos"},{"name":"links","description":"Link health"},{"name":"sales-page","description":"Sales page"},{"name":"publishing","description":"Publishing"},{"name":"profile","description":"Creator profile"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"An API key made in the Sceniq studio (Settings, API keys). Scopes: read, write (implies read), and the opt-in publish."}},"schemas":{"Error":{"type":"object","description":"Every error answer. Act on error.code; the message is for people.","properties":{"error":{"type":"object","properties":{"code":{"type":"string","description":"A stable code from the error reference (not_found, rate_limited ...)."},"message":{"type":"string","description":"What went wrong, in plain words."},"retryAfterMs":{"type":"integer","description":"rate_limited: how long to wait before the next request."},"details":{"type":"object","description":"not_publishable: { blocking: [{ code, message }] }, the publish gates that are open."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false},"GuideLink":{"type":"object","properties":{"kind":{"enum":["official","website","tickets","booking","status","timetable","tide","listing","social","authority","app","other"],"description":"What the link is for. official and website are the place's own pages; tickets and booking sell entry or rooms; status, timetable and tide carry live conditions; listing, social, authority and app cover the rest."},"label":{"type":"string","description":"The link text buyers see, at most 60 characters. Without it the apps name the link by its kind."},"url":{"type":"string","description":"An http or https page. http is accepted with a warning."},"value":{"type":"string","description":"A channel that is not a URL, at most 200 characters, for example a WeChat mini program and its search term."},"note":{"type":"string","description":"One line of context shown under the link, at most 300 characters."}},"required":["kind"],"additionalProperties":false,"description":"A link with a purpose: the official page, tickets, a live status page, a timetable. Spots, places and areas carry up to 12. Each needs a url or a value.","x-group":"Planning facts"},"StatusNotice":{"type":"object","properties":{"state":{"enum":["open","partly_closed","closed","reopening"],"description":"open, partly_closed, closed or reopening. reopening with until means it reopens on that day."},"note":{"type":"string","description":"What is closed or changed, in the creator's words, at most 500 characters."},"since":{"type":"string","description":"The day the state began (YYYY-MM-DD)."},"until":{"type":"string","description":"The day the state is expected to end (YYYY-MM-DD). Must not be before since."},"sourceUrl":{"type":"string","description":"The page that announced it (http or https)."},"checkedOn":{"type":"string","description":"The day the value was last checked against its source (YYYY-MM-DD)."}},"required":["state"],"additionalProperties":false,"description":"A closure or works notice that goes out of date. Buyers stop seeing it after until; readiness and list_stale_notices flag it once it ran out.","x-group":"Planning facts"},"Fee":{"type":"object","properties":{"label":{"type":"string","description":"What the fee is for, at most 80 characters (Adult entry, Car park, Boat transfer)."},"amount":{"type":"number","description":"The price in major units (40, 12.5). Needs currency. Absent when the fee is free or left to the official page."},"currency":{"type":"string","description":"ISO 4217 code (USD, EUR, ARS). Required with amount."},"free":{"type":"boolean","description":"true for no charge. Cannot be combined with an amount."},"seeOfficial":{"type":"boolean","description":"true for a price the guide leaves to the official page on purpose (it changes too often to copy)."},"per":{"enum":["person","vehicle","night","group","entry","day","hour"],"description":"What one amount pays for: person, vehicle, night, group, entry, day or hour."},"audience":{"enum":["all","adult","child","foreign","domestic","resident","student","senior"],"description":"Who pays this rate: all, adult, child, foreign, domestic, resident, student or senior."},"paidWhere":{"enum":["online","on_site","in_tour"],"description":"Where it is paid: online, on_site or in_tour (part of a tour price)."},"payment":{"enum":["cash_only","card_only","cash_or_card"],"description":"How it can be paid: cash_only, card_only or cash_or_card."},"note":{"type":"string","description":"One line of context, at most 300 characters (free on the first Sunday of the month)."},"validFrom":{"type":"string","description":"The first day the price applies (YYYY-MM-DD)."},"validUntil":{"type":"string","description":"The last day the price applies (YYYY-MM-DD). Readiness flags the row after it."},"sourceUrl":{"type":"string","description":"The page the price comes from (http or https)."},"checkedOn":{"type":"string","description":"The day the value was last checked against its source (YYYY-MM-DD)."}},"required":["label"],"additionalProperties":false,"description":"One fee or ticket as the source states it. The amount is information for buyers, never charged by Sceniq. Buyers see it with an as-of date; readiness flags rows past validUntil or unchecked for a year.","x-group":"Planning facts"},"Schedule":{"type":"object","properties":{"hours":{"type":"array","items":{"$ref":"#/components/schemas/HoursBand"},"description":"Up to 24 bands; the last matching band wins."},"specialDays":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string","description":"The day (YYYY-MM-DD). Give a date or a rule."},"rule":{"type":"string","description":"A recurring day in words, at most 120 characters (first Sunday of the month)."},"closed":{"type":"boolean","description":"true when the place is closed that day."},"open":{"type":"string","description":"Opening time that day as HH:MM, or sunrise or sunset."},"close":{"type":"string","description":"Closing time that day as HH:MM, or sunrise or sunset."},"note":{"type":"string","description":"One line for the day, at most 200 characters."}},"additionalProperties":false},"description":"Up to 40 days that differ from the bands: a date or a rule, closed or with their own times."},"slots":{"type":"object","properties":{"first":{"type":"string","description":"The first entry time as HH:MM."},"last":{"type":"string","description":"The last entry time as HH:MM."},"everyMin":{"type":"number","description":"Minutes between entries."},"cap":{"type":"number","description":"People per slot, when the source states it (1 to 100,000)."},"note":{"type":"string","description":"One line about booking a slot, at most 200 characters."}},"required":["first","last","everyMin"],"additionalProperties":false,"description":"Timed entry: entries every everyMin minutes from first to last."},"validFrom":{"type":"string","description":"The first day these hours apply (YYYY-MM-DD)."},"validUntil":{"type":"string","description":"The last day these hours apply (YYYY-MM-DD)."},"sourceUrl":{"type":"string","description":"The page the hours come from (http or https)."},"checkedOn":{"type":"string","description":"The day the value was last checked against its source (YYYY-MM-DD)."},"note":{"type":"string","description":"A note for the whole schedule, at most 500 characters."}},"additionalProperties":false,"description":"Structured opening hours. The free-text hours stay the fallback; the apps show today's hours in the spot's time zone. Readiness flags a schedule past validUntil.","x-group":"Planning facts"},"HoursBand":{"type":"object","properties":{"from":{"type":"string","description":"First day of the band as MM-DD. Absent means the start of the year."},"to":{"type":"string","description":"Last day of the band as MM-DD. May wrap over the new year (from 11-01 to 03-31)."},"weekdays":{"type":"array","items":{"type":"number"},"description":"The weekdays it covers, 1 (Monday) to 7 (Sunday). Absent means every day."},"closed":{"type":"boolean","description":"true when the place is closed in this band. Otherwise open and close are required."},"open":{"type":"string","description":"Opening time as HH:MM, or sunrise or sunset."},"close":{"type":"string","description":"Closing time as HH:MM, or sunrise or sunset."},"openOffsetMin":{"type":"number","description":"Minutes around a sun anchor for open (-240 to 240; -60 is an hour before sunrise)."},"closeOffsetMin":{"type":"number","description":"Minutes around a sun anchor for close (-240 to 240)."},"lastEntry":{"type":"string","description":"Last entry as HH:MM."},"leaveBy":{"type":"string","description":"The time visitors must be out as HH:MM."},"note":{"type":"string","description":"One line for the band, at most 200 characters."}},"additionalProperties":false,"description":"One band of opening hours: a date range, weekdays, and open and close times. The last matching band wins, so list the year-round band first and the exceptions after it.","x-group":"Planning facts"},"SpotPin":{"type":"object","properties":{"kind":{"enum":["viewpoint","entrance","gate","trailhead","parking","stop","pier","summit","other"],"description":"viewpoint, entrance, gate, trailhead, parking, stop, pier, summit or other."},"label":{"type":"string","description":"What buyers read next to the pin, at most 80 characters (South rim viewpoint)."},"lat":{"type":"number","description":"Latitude in decimal degrees (-90 to 90), from the creator's material or a cited source."},"lon":{"type":"number","description":"Longitude in decimal degrees (-180 to 180)."},"months":{"type":"array","items":{"type":"number"},"description":"The months the point is reachable (1 to 12). Absent means all year."},"note":{"type":"string","description":"One line of context, at most 300 characters."}},"required":["kind","label","lat","lon"],"additionalProperties":false,"description":"A point that belongs to a spot besides its main pin: where visitors stand, enter, start walking or leave the car. Each gets its own map links and a place on the web map. At most 12 per spot.","x-group":"Planning facts"},"MapLink":{"type":"object","properties":{"label":{"type":"string","description":"The pill text, at most 40 characters."},"url":{"type":"string","description":"An https page or an allowlisted map link."}},"required":["label","url"],"additionalProperties":false,"description":"An extra map link drawn as a map pill on the spot (a Swisstopo view, a trailhead in Apple Maps). For official, ticket or status pages use links instead. At most 8 per spot.","x-group":"Planning facts"},"AccessRule":{"type":"object","properties":{"text":{"type":"string","description":"The rule in the creator's words, at most 300 characters."},"kind":{"enum":["reservation","permit","guide","registration","no_independent_travel","vehicle","other"],"description":"reservation, permit, guide, registration, no_independent_travel, vehicle or other."},"months":{"type":"array","items":{"type":"number"},"description":"The months the rule applies (1 to 12); the apps show it only then. Absent means all year."},"appliesTo":{"enum":["car","all"],"description":"car for a rule that only binds drivers (a timed entry for vehicles), all for everyone."},"bookingOpens":{"type":"string","description":"When booking opens, in words, at most 100 characters (90 days ahead at 07:00)."},"sourceUrl":{"type":"string","description":"The page that states the rule (http or https)."}},"required":["text"],"additionalProperties":false,"description":"A rule for getting in: a reservation, a permit, a registration, a required guide. Used in arrival.rules and on areas; at most 20.","x-group":"Planning facts"},"Restriction":{"type":"object","properties":{"kind":{"enum":["no_photo","wide_only","no_drone","no_entry","no_stopping","no_parking","other"],"description":"no_photo, wide_only (shown as Wide shots only), no_drone, no_entry, no_stopping, no_parking or other."},"label":{"type":"string","description":"The rule as buyers read it, at most 80 characters."},"note":{"type":"string","description":"More context, at most 300 characters."},"lat":{"type":"number","description":"Latitude of the point the rule applies around."},"lon":{"type":"number","description":"Longitude of the point the rule applies around."},"radiusM":{"type":"number","description":"The radius around lat and lon in meters (1 to 100,000)."},"line":{"type":"array","items":{"type":"array","items":{"type":"number"}},"description":"A stretch of road or trail instead of a point: 2 to 200 [lon, lat] positions."},"sourceUrl":{"type":"string","description":"The page that states the rule (http or https)."}},"required":["kind","label"],"additionalProperties":false,"description":"A rule on site with an optional place: no photos here, no drones, no stopping on this road. At most 20 per spot.","x-group":"Planning facts"},"SpotFeature":{"type":"object","properties":{"name":{"type":"string","description":"The part's name, at most 80 characters."},"note":{"type":"string","description":"What to know about it, at most 500 characters."},"hours":{"type":"string","description":"Its hours in words, at most 200 characters."},"entry":{"type":"string","description":"Its entry rule or price in words, at most 200 characters."},"season":{"type":"string","description":"When it is open in words, at most 200 characters."},"fees":{"type":"array","items":{"$ref":"#/components/schemas/Fee"},"description":"Its own fees, as the spot's fees."},"status":{"$ref":"#/components/schemas/StatusNotice","description":"Its own closure notice."},"url":{"type":"string","description":"Its own page (http or https)."}},"required":["name"],"additionalProperties":false,"description":"A part of the site with its own rules: a monastery's closing day, a ticketed skyway, a museum inside a park. At most 12 per spot.","x-group":"Planning facts"},"SpotEvent":{"type":"object","properties":{"name":{"type":"string","description":"The event's name, at most 80 characters."},"when":{"type":"string","description":"When, in words, at most 200 characters (every night at 19:45 and 20:45)."},"dates":{"type":"array","items":{"type":"string"},"description":"Exact dates when known (YYYY-MM-DD, up to 60). Readiness lists events whose dates have all passed."},"months":{"type":"array","items":{"type":"number"},"description":"The months it happens (1 to 12)."},"url":{"type":"string","description":"The event's page (http or https)."},"free":{"type":"boolean","description":"true when it costs nothing to watch."},"note":{"type":"string","description":"One line of context, at most 300 characters."}},"required":["name","when"],"additionalProperties":false,"description":"A recurring or one-off event worth timing a visit for: a light show, a festival, a tide. The apps show the next listed date. At most 12 per spot.","x-group":"Planning facts"},"FoodNote":{"type":"object","properties":{"status":{"enum":["included","none_nearby","bring_your_own"],"description":"included (meals come with the lodge or boat), none_nearby, or bring_your_own."},"note":{"type":"string","description":"One line of context, at most 300 characters."}},"required":["status"],"additionalProperties":false,"description":"Why a spot lists no food places.","x-group":"Planning facts"},"TripFacts":{"type":"object","properties":{"elevationM":{"type":"number","description":"Elevation in meters (-500 to 9,000). 0 is a stated sea level; absent is unknown."},"elevationRefersTo":{"enum":["viewpoint","summit","ground","water","trailhead"],"description":"What the elevation measures: viewpoint, summit, ground, water or trailhead."},"elevationSource":{"type":"string","description":"Where the number comes from, at most 300 characters."},"busyness":{"type":"number","description":"Crowds from 1 (quiet) to 5 (packed), shown as Crowdedness."},"bestSeason":{"type":"string","description":"The best season in words, at most 200 characters."}},"additionalProperties":false,"description":"The planning stats bar on a spot: elevation, crowds and best season.","x-group":"Planning facts"},"SiteChange":{"type":"object","properties":{"on":{"type":"string","description":"The day of the change (YYYY-MM-DD). Required."},"note":{"type":"string","description":"What changed, at most 300 characters."}},"required":["on"],"additionalProperties":false,"description":"The day something at the spot changed (a bridge replaced, boats banned). Readiness flags photos captured before it.","x-group":"Planning facts"},"SourceRef":{"type":"object","properties":{"url":{"type":"string","description":"The page, API or archive copy the facts come from (http or https)."},"title":{"type":"string","description":"A name for a source without a URL (a park leaflet, a phone call with the operator), at most 200 characters."},"kind":{"enum":["page","api","archive","document","other"],"description":"page, api, archive, document or other."},"capturedOn":{"type":"string","description":"The day the source was read (YYYY-MM-DD)."},"note":{"type":"string","description":"What the source says or why it was chosen, at most 500 characters."},"supports":{"type":"array","items":{"type":"string"},"description":"Which facts it backs, up to 12 entries of at most 60 characters (fees, arrival.operating, lat/lon)."},"conflict":{"type":"boolean","description":"true when this source disagrees with another on the facts it backs. Say which one the value follows in note or reviewNotes."}},"additionalProperties":false,"description":"Research evidence for the creator's review. Never shown to buyers. Needs a url or a title; at most 40 per row.","x-group":"Planning facts"},"Arrival":{"type":"object","properties":{"byCar":{"type":"object","properties":{"directions":{"type":"string","description":"The drive in words, at most 2,000 characters."},"parking":{"type":"string","description":"Where to park, at most 1,000 characters."},"walkToSpotMin":{"type":"number","description":"Minutes on foot from the car to the spot."},"walkRoundTrip":{"type":"boolean","description":"true when walkToSpotMin is there and back."},"none":{"type":"boolean","description":"true when the spot has no car access."},"note":{"type":"string","description":"One more line about driving, at most 500 characters."}},"additionalProperties":false,"description":"Driving and parking."},"byTrainBus":{"type":"object","properties":{"route":{"type":"string","description":"The connection in words, at most 2,000 characters."},"walkFromStopMin":{"type":"number","description":"Minutes on foot from the stop to the spot."},"walkRoundTrip":{"type":"boolean","description":"true when walkFromStopMin is there and back."},"none":{"type":"boolean","description":"true when there is no public transport."},"note":{"type":"string","description":"One more line about public transport, at most 500 characters."}},"additionalProperties":false,"description":"Public transport."},"byBoat":{"type":"string","description":"The boat connection in words, at most 2,000 characters."},"byAir":{"type":"object","properties":{"airports":{"type":"array","items":{"type":"string"},"description":"Up to 8 IATA or ICAO codes (LUA, VNLK)."},"route":{"type":"string","description":"The flight in words, at most 2,000 characters."},"minutes":{"type":"number","description":"Flight time in minutes."},"operatorUrl":{"type":"string","description":"The operator's page (http or https)."},"luggageKg":{"type":"number","description":"The luggage limit in kilograms (1 to 200)."},"none":{"type":"boolean","description":"true when there is no air access."},"note":{"type":"string","description":"One more line about flying, at most 500 characters."}},"additionalProperties":false,"description":"Flights or helicopter."},"onFoot":{"$ref":"#/components/schemas/ArrivalModeBlock","description":"Walking in."},"byBike":{"$ref":"#/components/schemas/ArrivalModeBlock","description":"Cycling in."},"bestTime":{"type":"string","description":"The best time to go in words, at most 1,000 characters."},"operating":{"type":"string","description":"When the access runs (seasons, hours of a road or a ferry), at most 2,000 characters."},"approaches":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string","description":"The approach's name, at most 80 characters (Argentine side)."},"country":{"type":"string","description":"ISO 3166-1 alpha-2 code of the country it starts in (AR)."},"legs":{"type":"array","items":{"type":"object","properties":{"mode":{"enum":["car","bus","train","tram","metro","cable_car","funicular","boat","ferry","plane","helicopter","shuttle","jeep","walk","bike","taxi","other"],"description":"car, bus, train, tram, metro, cable_car, funicular, boat, ferry, plane, helicopter, shuttle, jeep, walk, bike, taxi or other."},"from":{"type":"string","description":"Where the leg starts, at most 120 characters."},"to":{"type":"string","description":"Where the leg ends, at most 120 characters."},"minutes":{"type":"number","description":"Minutes the leg takes."},"roundTrip":{"type":"boolean","description":"true when minutes is there and back."},"price":{"type":"string","description":"The leg's price in words, at most 80 characters."},"payment":{"type":"string","description":"How the leg is paid, at most 80 characters."},"note":{"type":"string","description":"One line for the leg, at most 300 characters."}},"required":["mode"],"additionalProperties":false},"description":"Up to 12 legs in order."},"hours":{"type":"string","description":"When the approach runs, at most 300 characters."},"entry":{"type":"string","description":"What entry takes on this side, at most 300 characters."},"note":{"type":"string","description":"One more line, at most 500 characters."},"lat":{"type":"number","description":"Latitude of the approach's start."},"lon":{"type":"number","description":"Longitude of the approach's start."}},"required":["label"],"additionalProperties":false},"description":"Up to 6 ways in, for spots with several approaches or chains of legs (a flight, then a jeep, then a walk)."},"rules":{"type":"array","items":{"$ref":"#/components/schemas/AccessRule"},"description":"Up to 20 access rules (reservations, permits), each shown in its months."}},"additionalProperties":false,"description":"How to get there, by mode, plus whole approaches as chains of legs and the access rules by month. Every block is optional; none true on a mode says there is no such access, which reads differently from an empty field.","x-group":"Arrival"},"ArrivalModeBlock":{"type":"object","properties":{"route":{"type":"string","description":"The way in words, at most 2,000 characters."},"minutes":{"type":"number","description":"Minutes it takes."},"roundTrip":{"type":"boolean","description":"true when minutes is there and back."},"none":{"type":"boolean","description":"true when this mode is not possible."},"note":{"type":"string","description":"One more line, at most 500 characters."}},"additionalProperties":false,"description":"One way in on foot or by bike.","x-group":"Arrival"},"Area":{"type":"object","properties":{"id":{"type":"string","description":"The area's id, minted by set_area; spots point at it with areaId."},"name":{"type":"string","description":"The area's name, at most 100 characters (Yellowstone National Park)."},"kind":{"enum":["park","reserve","island","region","city","other"],"description":"park, reserve, island, region, city or other, shown as the area's label (Park, Island). Absent reads as other (Area)."},"note":{"type":"string","description":"What applies across the area, in the creator's words, at most 1,000 characters."},"season":{"type":"string","description":"The area's season in words, at most 300 characters (roads open May to October)."},"rules":{"type":"array","items":{"$ref":"#/components/schemas/AccessRule"},"description":"Up to 20 access rules for the whole area (permits, timed entry), each shown in its months."},"fees":{"type":"array","items":{"$ref":"#/components/schemas/Fee"},"description":"Up to 30 fees for the whole area (park entry, a vehicle pass)."},"links":{"type":"array","items":{"$ref":"#/components/schemas/GuideLink"},"description":"Up to 12 links for the whole area."},"status":{"$ref":"#/components/schemas/StatusNotice","description":"A closure or works notice for the whole area."},"sources":{"type":"array","items":{"$ref":"#/components/schemas/SourceRef"},"description":"Up to 40 research sources, never shown to buyers."}},"required":["id","name"],"additionalProperties":false,"description":"A park, reserve, island, region or city whose rules, fees, season, links and status apply to every spot that points at it (areaId). Stored once per guide, at most 50; set_area writes one.","x-group":"Guide settings"},"PlaceConditions":{"type":"object","properties":{"minAge":{"type":"number","description":"Minimum age, a whole number from 1 to 99, shown as Age 16+."},"guestsOnly":{"type":"boolean","description":"true shows Guests only."},"swimmersOnly":{"type":"boolean","description":"true shows Swimmers only."},"luggageKg":{"type":"number","description":"The luggage limit in kilograms (1 to 200), shown as Luggage up to 15 kg."},"soldAsPackage":{"type":"boolean","description":"true shows Sold as a package."},"cashOnly":{"type":"boolean","description":"true shows Cash only."}},"additionalProperties":false,"description":"Conditions for a place, shown as chips on its card. Only true flags are stored; false and absent show nothing.","x-group":"Place details"},"ParkingInfo":{"type":"object","properties":{"fillsBy":{"type":"string","description":"When the lot is usually full, at most 80 characters (10:00, by 9 in summer), shown as Fills by."},"rule":{"type":"string","description":"What is allowed, at most 300 characters (the only legal pullout)."}},"additionalProperties":false,"description":"Parking facts shown on a place's card.","x-group":"Place details"},"TransportInfo":{"type":"object","properties":{"stops":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"The stop's name, at most 100 characters. Required."},"lat":{"type":"number","description":"Latitude of the stop. Give lat and lon together; the stop then links to a map."},"lon":{"type":"number","description":"Longitude of the stop."},"registerId":{"type":"string","description":"The stop's id in a public register (an NSR or GTFS stop id), at most 80 characters."},"note":{"type":"string","description":"One line about the stop, at most 200 characters."}},"required":["name"],"additionalProperties":false},"description":"Up to 30 stops, in the order buyers see them."},"serviceDays":{"type":"array","items":{"type":"number"},"description":"The weekdays it runs, 1 (Monday) to 7 (Sunday). On fewer than seven days buyers see Runs Mon to Fri."},"timetableUrl":{"type":"string","description":"The timetable page (http or https), shown as a Timetable link."},"timetableValidFrom":{"type":"string","description":"The first day the timetable applies (YYYY-MM-DD)."},"timetableValidUntil":{"type":"string","description":"The last day the timetable applies (YYYY-MM-DD), not before timetableValidFrom. Buyers see Timetable valid until that day."},"verifyBeforeTravel":{"type":"boolean","description":"true shows Check the timetable before you travel."}},"additionalProperties":false,"description":"Transport details of a place (a ferry, a bus line, a cable car): its stops, the days it runs and how long the timetable is valid. list_stale_notices lists a timetable past timetableValidUntil.","x-group":"Place details"},"ActivityInfo":{"type":"object","properties":{"meetingPoint":{"type":"string","description":"Where to meet, at most 200 characters, shown as Meeting point."},"meetingLat":{"type":"number","description":"Latitude of the meeting point. Give meetingLat and meetingLon together."},"meetingLon":{"type":"number","description":"Longitude of the meeting point."},"durationMin":{"type":"number","description":"How long it takes in minutes (1 to 100,000), shown as Duration."},"departures":{"type":"string","description":"When it departs, in words, at most 300 characters (daily at 09:00 and 14:00), shown as Departures."},"requiredToSee":{"type":"boolean","description":"true when a tour is the only way to see the spot (authorized tours at Antelope Canyon), shown as Needed to see the spot."},"authorizedBy":{"type":"string","description":"Who authorizes the operator, at most 120 characters, shown as Authorized by <name>."},"authorizedByUrl":{"type":"string","description":"The authorizing body's page (http or https), linked from that line."}},"additionalProperties":false,"description":"Details of a tour or activity (kind activity): where it meets, how long it takes, when it departs and who authorizes it.","x-group":"Place details"},"RouteSeason":{"type":"object","properties":{"months":{"type":"array","items":{"type":"number"},"description":"The months it can be walked (1 to 12). Absent means all year."},"closureNote":{"type":"string","description":"What closes and when, at most 500 characters (stairs chained November to April)."},"statusUrl":{"type":"string","description":"The page with the current conditions (http or https), linked from the season notice."}},"additionalProperties":false,"description":"When a route can be walked. Buyers opening it outside its months see it as out of season, with the closure note.","x-group":"Route facts"},"RouteVariant":{"type":"object","properties":{"name":{"type":"string","description":"The variant's name, at most 80 characters. Required."},"start":{"type":"string","description":"Where it starts when that differs, at most 200 characters."},"extraKm":{"type":"number","description":"Kilometers it adds, negative when shorter (-1,000 to 1,000)."},"extraMin":{"type":"number","description":"Minutes it adds, negative when faster (-10,000 to 10,000)."},"purpose":{"type":"string","description":"Why take it, at most 300 characters."}},"required":["name"],"additionalProperties":false,"description":"An alternative to the main route: a detour, a shortcut, another start. At most 12 per route.","x-group":"Route facts"},"RouteStage":{"type":"object","properties":{"name":{"type":"string","description":"The stage's name, at most 120 characters (Day 1: Refugio Grey to Paine Grande). Required."},"km":{"type":"number","description":"Distance in kilometers (0 to 1,000)."},"min":{"type":"number","description":"Duration in minutes (0 to 10,000)."},"gainM":{"type":"number","description":"Elevation gain in meters (0 to 10,000)."},"note":{"type":"string","description":"One line for the stage, at most 300 characters."}},"required":["name"],"additionalProperties":false,"description":"One day or leg of a multi-day trek, in order. At most 40 per route.","x-group":"Route facts"},"RouteSegment":{"type":"object","properties":{"name":{"type":"string","description":"The section's name, at most 120 characters. Required."},"km":{"type":"number","description":"Its length in kilometers (0 to 1,000)."},"accessNote":{"type":"string","description":"What access it needs, at most 300 characters (permit by lottery)."}},"required":["name"],"additionalProperties":false,"description":"A section of a route with its own access (free to Scout Lookout, a permit for the chains). At most 20 per route.","x-group":"Route facts"},"FigureSource":{"type":"object","properties":{"field":{"enum":["durationMin","distanceKm","gainM","descentM","sacGrade"],"description":"The number it backs: durationMin, distanceKm, gainM, descentM or sacGrade."},"kind":{"enum":["sourced","computed"],"description":"sourced (taken from a source) or computed (worked out, for example from the GPX track)."},"url":{"type":"string","description":"The source page (http or https)."},"note":{"type":"string","description":"How the number was found or worked out, at most 300 characters."}},"required":["field","kind"],"additionalProperties":false,"description":"Where one of a route's numbers comes from. At most 20 per route.","x-group":"Route facts"},"TransitNote":{"type":"object","properties":{"mode":{"enum":["train","bus","cable_car","car","boat","ferry","plane"],"description":"train, bus, cable_car, car, boat, ferry or plane (shown as Flight)."},"note":{"type":"string","description":"The note in words: the connection, where to change, the last departure."}},"required":["mode","note"],"additionalProperties":false,"description":"A transit note for one mode, shown under Transit on the route card. At most 20 per route; a row with an empty note is dropped.","x-group":"Route facts"},"ExtraProp":{"type":"object","properties":{"label":{"type":"string","description":"The row's label, at most 60 characters."},"value":{"type":"string","description":"The row's value, at most 500 characters."}},"required":["label","value"],"additionalProperties":false,"description":"A free label and value row the creator adds to a route or a place card. At most 24; a row with both sides empty is dropped, a half-empty one refused.","x-group":"Route facts"},"RouteTrack":{"type":"object","properties":{"coordinates":{"type":"array","items":{"type":"array","items":{"type":"number"}},"description":"Positions as [lon, lat] or [lon, lat, ele] (ele in meters), 2 to 1,000. Stored rounded to 6 decimals and whole meters."},"source":{"type":"string","description":"The file type the line came from: gpx or kml. Other values are dropped."},"fileName":{"type":"string","description":"The imported file's name, cut to 200 characters."}},"required":["coordinates"],"additionalProperties":false,"description":"The line of a route from the creator's GPX or KML file, drawn on the maps. 2 to 1,000 positions; simplify long recordings first.","x-group":"Route facts"},"PhotoShows":{"type":"object","properties":{"kind":{"enum":["spot","view_from_spot","nearby","approach","detail","other"],"description":"spot (the place itself), view_from_spot (the view from it), nearby (a sight near the spot; readiness then skips its distance check), approach (the way there), detail or other."},"label":{"type":"string","description":"What exactly it shows, at most 80 characters (the north face from the lake)."}},"required":["kind"],"additionalProperties":false,"description":"What a photo shows, for the creator's review and the readiness checks.","x-group":"Photo metadata"},"PhotoTakenAt":{"type":"object","properties":{"lat":{"type":"number","description":"Latitude in decimal degrees (-90 to 90)."},"lon":{"type":"number","description":"Longitude in decimal degrees (-180 to 180)."},"precision":{"enum":["gps","geocode","none"],"description":"gps (a camera or phone fix), geocode (looked up from a place name, often coarse on stock sites) or none (an estimate; readiness lists it as resting on judgement)."}},"required":["lat","lon","precision"],"additionalProperties":false,"description":"Where a photo was taken and how precise that is. Readiness flags a gps location more than 2 km from the spot's pin unless the photo shows a nearby sight.","x-group":"Photo metadata"},"MapRegion":{"type":"object","properties":{"label":{"type":"string","description":"A name buyers recognise for the region, at most 120 characters (Hokkaido, the Dolomites)."},"centerLat":{"type":"number","description":"Latitude of the opening center (-90 to 90), usually the middle of the spots."},"centerLon":{"type":"number","description":"Longitude of the opening center (-180 to 180)."},"defaultZoom":{"type":"number","description":"The opening zoom level, 0 to 22; 8 to 11 suits a region."},"bbox":{"type":"array","items":{"type":"number"},"description":"The bounding box as [west, south, east, north] in decimal degrees, exactly four numbers. It should contain every spot: readiness flags spots outside it."}},"additionalProperties":false,"description":"The map region the viewer opens on. set_guide_region replaces the whole object: fields left out are cleared.","x-group":"Guide settings"},"SocialLink":{"type":"object","properties":{"platform":{"enum":["instagram","tiktok","youtube"],"description":"instagram, tiktok or youtube."},"handle":{"type":"string","description":"The account name (@name). Required on the profile; the link pill shows it when there is no follower count."},"url":{"type":"string","description":"The profile page (https; set_profile_socials refuses other links). An empty url on a sales page falls back to the link built from platform and handle."},"followerCount":{"type":"number","description":"Followers as the creator states them, a whole number from 0, shown on the pill (12K) instead of the handle."}},"required":["platform","handle","url"],"additionalProperties":false,"description":"A social profile link: on the creator profile (set_profile_socials, at most 6) or on one sales page's about section (socialsOverride).","x-group":"Guide settings"},"ChapterIntro":{"type":"object","properties":{"coverKicker":{"type":"string","description":"The cover's eyebrow line, at most 120 characters (A Patagonia Field Guide)."},"coverTitle":{"type":"string","description":"The cover title, at most 160 characters. Absent means the guide's name."},"coverAuthor":{"type":"string","description":"The byline name, shown as By <name>, at most 120 characters. Absent means the creator's display name."},"coverAuthorPhotoStorageId":{"type":"string","x-sceniq-id":"_storage","description":"The byline photo, a storageId from an upload with target=blob. Absent means the creator's avatar."},"sections":{"type":"array","items":{"$ref":"#/components/schemas/IntroSection"},"description":"Up to 20 sections in reading order."}},"required":["sections"],"additionalProperties":false,"description":"The structured front matter of an intro chapter (set_chapter_intro): a cover with kicker, title and byline, then up to 20 sections. Strings are trimmed and empty ones dropped; the whole object is at most 150,000 characters of JSON. Photos are storageIds the intro owns: a write that drops one deletes the file (for a live guide, at the next publish).","x-group":"Chapters"},"IntroSection":{"type":"object","properties":{"kind":{"enum":["prose","chapters","collections"],"description":"prose (the default), chapters (a row for each other chapter of the guide) or collections (a card for each collection that has spots). The rows and cards derive from the guide; items only restyle them."},"kicker":{"type":"string","description":"The eyebrow above the title, at most 120 characters."},"title":{"type":"string","description":"The section title, at most 160 characters. Required."},"deck":{"type":"string","description":"The standfirst under the title, at most 500 characters."},"paragraphs":{"type":"array","items":{"type":"string"},"description":"Prose sections only: up to 30 paragraphs of at most 10,000 characters. Lines starting with \"- \" inside a paragraph render as a bulleted list."},"cells":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string","description":"The cell's title, at most 120 characters. Required unless the whole cell is empty, which drops it."},"body":{"type":"string","description":"The cell's text, at most 600 characters."}},"required":["title","body"],"additionalProperties":false},"description":"Prose sections only: up to 8 numbered cells (a plan in steps). A section with cells carries no paragraphs and no photo."},"photoStorageId":{"type":"string","x-sceniq-id":"_storage","description":"Prose sections only: the side photo, a storageId from an upload with target=blob."},"photoCredit":{"type":"string","description":"The side photo's credit, at most 80 characters, shown on the photo. Kept only with a photo; absent means the creator's own shot."},"items":{"type":"array","items":{"$ref":"#/components/schemas/IntroItem"},"description":"Chapters and collections sections only: up to 60 entries, each restyling one row or card."}},"required":["title"],"additionalProperties":false,"description":"One section of a chapter's front matter. A prose section carries text, a numbered grid or a side photo; a chapters or collections section lists the guide's chapters or collections and carries only kicker, title, deck and items.","x-group":"Chapters"},"IntroItem":{"type":"object","properties":{"collectionId":{"type":"string","x-sceniq-id":"collections","description":"The chapter (chapters section) or plain collection (collections section) of this guide the entry dresses, once per section."},"title":{"type":"string","description":"The name on the row or card, at most 120 characters. Absent means the chapter's or collection's name."},"line":{"type":"string","description":"Chapters sections only: the short line under the name, at most 200 characters. Absent means the chapter's description."},"color":{"type":"string","description":"Chapters sections only: the row's color bar as #rrggbb (stored lower case)."},"photoStorageId":{"type":"string","x-sceniq-id":"_storage","description":"Collections sections only: the card photo, a storageId from an upload with target=blob. Absent means the collection's cover."},"photoCredit":{"type":"string","description":"The card photo's credit, at most 80 characters. Kept only with a photo."}},"required":["collectionId"],"additionalProperties":false,"description":"The dressing of one row (chapters section) or card (collections section) of a chapter's front matter. An entry that sets nothing is dropped.","x-group":"Chapters"},"ListingConfig":{"type":"object","properties":{"hero":{"$ref":"#/components/schemas/HeroSection","description":"The top of the page, always shown."},"pitch":{"$ref":"#/components/schemas/PitchSection","description":"What's inside: boxes with a title, text and a photo or icon. Can be switched off."},"reviews":{"$ref":"#/components/schemas/ReviewsSection","description":"Testimonials. Can be switched off."},"gallery":{"$ref":"#/components/schemas/GallerySection","description":"Full-screen photos with captions. Can be switched off; off in a new draft."},"aboutCreator":{"$ref":"#/components/schemas/AboutCreatorSection","description":"The creator's bio, social links and video, with per-page overrides. Can be switched off."},"buyForm":{"$ref":"#/components/schemas/BuyFormSection","description":"The buy section with the checkout, always shown."},"faq":{"$ref":"#/components/schemas/FaqSection","description":"Questions and answers below the buy form. Can be switched off; off in a new draft. Absent on drafts saved before the section existed."},"sectionOrder":{"type":"array","items":{"enum":["pitch","reviews","gallery","aboutCreator","buyForm","faq"]},"description":"The page order of the sections below the hero: pitch, reviews, gallery, aboutCreator, buyForm and faq, each at most once. Missing sections follow in that default order; absent means the default."}},"required":["hero","pitch","reviews","gallery","aboutCreator","buyForm"],"additionalProperties":false,"description":"The sales page, always sent whole (read get_sales_page and edit that). Every save checks the list caps, that each media id is a product- or listing-owned photo of this guide, and the banned phrase about updates. The publish checks (a hero photo and title, 2 to 6 bullets, content in every enabled section) run when the creator publishes in the studio.","x-group":"Sales page"},"HeroSection":{"type":"object","properties":{"carousel":{"type":"array","items":{"$ref":"#/components/schemas/ListingSlide"},"description":"Up to 12 slides that turn automatically. Publishing needs at least one."},"title":{"type":"string","description":"The page title, usually the guide's name. Publishing needs one."},"headline":{"type":"string","description":"One line under the title, at most 200 characters. Absent or empty falls back to the guide's headline (update_guide)."},"kicker":{"type":"string","description":"An eyebrow above the title."},"bullets":{"type":"array","items":{"type":"object","properties":{"text":{"type":"string","description":"One selling point."},"order":{"type":"number","description":"Sort key, ascending; fractional values are fine."}},"required":["text","order"],"additionalProperties":false},"description":"The selling points: at most 6 on save, 2 to 6 and none empty to publish."},"collectionMediaId":{"type":"string","x-sceniq-id":"media","description":"An optional collage image, a product- or listing-owned photo of this guide, shown on the buy card beside the page on wide screens."}},"required":["carousel","title","bullets"],"additionalProperties":false,"description":"The top of the sales page, always shown: the photo carousel, title, headline, kicker and bullets.","x-group":"Sales page"},"ListingSlide":{"type":"object","properties":{"mediaId":{"type":"string","x-sceniq-id":"media","description":"A product- or listing-owned photo of this guide (list_media with marketingOnly true). Spot and chapter photos are refused."},"caption":{"type":"string","description":"The caption for this slide. Absent means the photo's own caption."},"order":{"type":"number","description":"Sort key, ascending; fractional values are fine."}},"required":["mediaId","order"],"additionalProperties":false,"description":"One photo of the hero carousel or the gallery, by media id. The photo's own credit shows with it.","x-group":"Sales page"},"PitchSection":{"type":"object","properties":{"enabled":{"type":"boolean","description":"false hides the section. Publishing an enabled section needs at least one box, each with a title."},"title":{"type":"string","description":"The section heading. Absent or empty shows What's inside."},"description":{"type":"string","description":"A line under the heading."},"imageAspect":{"enum":["3:2","1:1","4:5"],"description":"The crop of every box photo: 3:2, 1:1 or 4:5 (the default)."},"boxes":{"type":"array","items":{"type":"object","properties":{"mediaId":{"type":"string","x-sceniq-id":"media","description":"An optional photo on top of the box, a product- or listing-owned photo of this guide."},"emoji":{"type":"string","description":"An emoji the creator chose for the box's icon tile, shown when the box has no photo (beside the title when it has one). Agents leave it empty (no emoji in any field); without one the page picks an icon from the title."},"title":{"type":"string","description":"The box title. Publishing needs one on every box."},"description":{"type":"string","description":"The box text."},"order":{"type":"number","description":"Sort key, ascending; fractional values are fine."}},"required":["title","order"],"additionalProperties":false},"description":"Up to 24 boxes."}},"required":["enabled","boxes"],"additionalProperties":false,"description":"What's inside the guide, as boxes. Can be switched off.","x-group":"Sales page"},"ReviewsSection":{"type":"object","properties":{"enabled":{"type":"boolean","description":"false hides the section and the star rating under the hero title."},"source":{"enum":["product","platform","custom"],"description":"Where the testimonials come from: custom (the creator's own quotes in custom), platform (testimonials Sceniq curates) or product (labelled Buyer Reviews; the page currently shows the curated platform testimonials for it too)."},"heading":{"type":"string","description":"The section heading. Absent or empty shows the source's default: What people say (custom), Platform Reviews (platform) or Buyer Reviews (product)."},"custom":{"type":"array","items":{"$ref":"#/components/schemas/CustomReview"},"description":"The creator's testimonials, up to 12, shown when source is custom. Publishing an enabled custom section needs at least one."}},"required":["enabled","source"],"additionalProperties":false,"description":"Testimonials on the sales page. Can be switched off.","x-group":"Sales page"},"CustomReview":{"type":"object","properties":{"name":{"type":"string","description":"The reviewer's name. Publishing needs one."},"quote":{"type":"string","description":"The quote, word for word. Publishing needs one; quotes over 140 characters collapse behind Read more."},"rating":{"type":"number","description":"Stars as a whole number from 1 to 5; stars show only when it is set. Never invent one."},"verified":{"type":"boolean","description":"Ignored: every save removes it, so testimonials the creator enters never show a verified badge."},"platform":{"enum":["instagram","tiktok","youtube"],"description":"instagram, tiktok or youtube. With a handle, the handle links to the profile."},"handle":{"type":"string","description":"The reviewer's handle, shown with a leading @."},"followerCount":{"type":"number","description":"The reviewer's followers as a whole number from 0, shown next to the handle (12K)."},"avatarMediaId":{"type":"string","x-sceniq-id":"media","description":"The reviewer's photo, a product- or listing-owned photo of this guide."},"order":{"type":"number","description":"Sort key, ascending; fractional values are fine."}},"required":["name","quote","order"],"additionalProperties":false,"description":"A testimonial the creator supplied (reviews source custom), quoted verbatim in every language. Only real quotes the creator gives you; never invent one.","x-group":"Sales page"},"GallerySection":{"type":"object","properties":{"enabled":{"type":"boolean","description":"false hides the section. Publishing an enabled gallery needs at least one slide."},"title":{"type":"string","description":"The section heading. Absent or empty shows From the field."},"description":{"type":"string","description":"A line under the heading."},"slides":{"type":"array","items":{"$ref":"#/components/schemas/ListingSlide"},"description":"Up to 48 slides."}},"required":["enabled","slides"],"additionalProperties":false,"description":"Full-screen photos with captions. Can be switched off; off in a new draft.","x-group":"Sales page"},"AboutCreatorSection":{"type":"object","properties":{"enabled":{"type":"boolean","description":"false hides the section. Publishing an enabled section needs a bio, social links or a video."},"descriptionOverride":{"type":"string","description":"The about text for this page only. Absent means the creator's profile bio."},"socialsOverride":{"type":"array","items":{"$ref":"#/components/schemas/SocialLink"},"description":"Social links for this page only; [] shows none. Absent means the profile's social links."},"video":{"$ref":"#/components/schemas/IntroVideo","description":"A video for the section. Absent shows no video."}},"required":["enabled"],"additionalProperties":false,"description":"The creator's bio, social links and video. Bio and social links come from the creator profile unless this page overrides them. Can be switched off.","x-group":"Sales page"},"IntroVideo":{"type":"object","properties":{"provider":{"enum":["youtube","vimeo","upload"],"description":"youtube, vimeo or upload (a video file stored on Sceniq)."},"youtubeId":{"type":"string","description":"For youtube: the video id (the v= value of a watch link), never a URL or an embed code."},"vimeoId":{"type":"string","description":"For vimeo: the numeric id from the video's link. The player loads only after a click."},"storageId":{"type":"string","x-sceniq-id":"_storage","description":"For upload: the stored video file. The API cannot upload videos; keep the value you read."},"fileUrl":{"type":"string","description":"For upload: a direct link to the video file, used when there is no storageId."},"caption":{"type":"string","description":"A line under the video."}},"required":["provider"],"additionalProperties":false,"description":"A video referenced by provider and id, never by an embed code.","x-group":"Sales page"},"BuyFormSection":{"type":"object","properties":{"ctaLabel":{"type":"string","description":"The label of every buy button on the page, at most 60 characters. Absent or empty falls back to the guide's purchaseButtonText, then Get the guide."},"reassuranceText":{"type":"string","description":"A short line over the bottom of the checkout photo, or above the checkout without one."},"imageMediaId":{"type":"string","x-sceniq-id":"media","description":"A photo above the checkout in a 3:2 crop, a product- or listing-owned photo of this guide."}},"additionalProperties":false,"description":"The buy section with the checkout, always shown.","x-group":"Sales page"},"FaqSection":{"type":"object","properties":{"enabled":{"type":"boolean","description":"false hides the section. Publishing an enabled FAQ needs at least one item, each with a question and an answer."},"title":{"type":"string","description":"The section heading. Absent or empty shows Common questions."},"items":{"type":"array","items":{"type":"object","properties":{"question":{"type":"string","description":"The question."},"answer":{"type":"string","description":"The answer."},"order":{"type":"number","description":"Sort key, ascending; fractional values are fine."}},"required":["question","answer","order"],"additionalProperties":false},"description":"Up to 12 items."}},"required":["enabled","items"],"additionalProperties":false,"description":"Questions and answers below the buy form. Off in a new draft.","x-group":"Sales page"},"Spot":{"type":"object","properties":{"spotId":{"type":"string","x-sceniq-id":"spots","description":"The spot's id."},"spotKey":{"type":"string","description":"The spot's stable key within the guide; chapters and routes reference spots by it."},"productId":{"type":"string","x-sceniq-id":"products","description":"The guide the spot belongs to."},"title":{"type":"string","description":"The place name."},"kicker":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The short line above the title (region or type)."},"lat":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Latitude in decimal degrees, or null when the pin is not set yet."},"lon":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Longitude in decimal degrees, or null when the pin is not set yet."},"mapsUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The creator's own map link."},"shortDescription":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"One or two sentences for the card."},"longDescription":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The full write-up."},"color":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Pin color as a hex value, or null for the default."},"cardOrientation":{"enum":["portrait","landscape"],"description":"Photo framing in the viewer."},"customValues":{"type":"object","additionalProperties":{},"description":"Custom property values keyed by property key; option values are option ids."},"tripFacts":{"anyOf":[{"$ref":"#/components/schemas/TripFacts"},{"type":"null"}],"description":"The planning stats bar."},"arrival":{"anyOf":[{"$ref":"#/components/schemas/Arrival"},{"type":"null"}],"description":"How to get there."},"mapLinks":{"type":"array","items":{"$ref":"#/components/schemas/MapLink"},"description":"Extra map links, drawn as map pills."},"imagesEnabled":{"type":"boolean","description":"false hides the photo section from buyers."},"customPropsEnabled":{"type":"boolean","description":"false hides the custom properties from buyers."},"archived":{"type":"boolean","description":"true when the spot is hidden from buyers but kept."},"ref":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Your own stable key for upsert_spots."},"accessMode":{"anyOf":[{"enum":["drive_up","short_walk","hike","multi_day","boat","cable_car","train","flight","tour_only","aerial_only"]},{"type":"null"}],"description":"How visitors reach the spot, shown as Accessibility."},"pinLabel":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"What the main pin marks, for a spot that is an area or a line."},"pins":{"type":"array","items":{"$ref":"#/components/schemas/SpotPin"},"description":"Extra points: viewpoints, entrances, trailheads, parking."},"links":{"type":"array","items":{"$ref":"#/components/schemas/GuideLink"},"description":"Links with a purpose."},"status":{"anyOf":[{"$ref":"#/components/schemas/StatusNotice"},{"type":"null"}],"description":"A closure or works notice."},"fees":{"type":"array","items":{"$ref":"#/components/schemas/Fee"},"description":"Fees and tickets."},"schedule":{"anyOf":[{"$ref":"#/components/schemas/Schedule"},{"type":"null"}],"description":"Structured opening hours."},"features":{"type":"array","items":{"$ref":"#/components/schemas/SpotFeature"},"description":"Parts of the site with their own rules."},"restrictions":{"type":"array","items":{"$ref":"#/components/schemas/Restriction"},"description":"Rules on site."},"events":{"type":"array","items":{"$ref":"#/components/schemas/SpotEvent"},"description":"Events worth timing a visit for."},"food":{"anyOf":[{"$ref":"#/components/schemas/FoodNote"},{"type":"null"}],"description":"Why the spot lists no food places."},"areaId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The area (park, island, region) the spot sits in."},"timeZone":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"IANA time zone, derived from the pin unless set by hand."},"timeZoneManual":{"type":"boolean","description":"true when the time zone was set by hand rather than from the pin."},"customNotes":{"type":"object","additionalProperties":{"type":"string"},"description":"One short note per custom property value, keyed by property key."},"sources":{"type":"array","items":{"$ref":"#/components/schemas/SourceRef"},"description":"Research evidence for the review, never shown to buyers."},"reviewNotes":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Notes for the creator's review, never shown to buyers."},"factsCheckedOn":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The day the facts were last checked (YYYY-MM-DD)."},"reviewBy":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The day the facts need a new check (YYYY-MM-DD)."},"siteChange":{"anyOf":[{"$ref":"#/components/schemas/SiteChange"},{"type":"null"}],"description":"The day something at the spot changed."},"createdAt":{"type":"number","description":"When the row was created (Unix time in milliseconds)."},"updatedAt":{"type":"number","description":"When the row last changed (Unix time in milliseconds)."}},"required":["spotId","spotKey","productId","title","kicker","lat","lon","mapsUrl","shortDescription","longDescription","color","cardOrientation","customValues","tripFacts","arrival","mapLinks","imagesEnabled","customPropsEnabled","archived","ref","accessMode","pinLabel","pins","links","status","fees","schedule","features","restrictions","events","food","areaId","timeZone","timeZoneManual","customNotes","sources","reviewNotes","factsCheckedOn","reviewBy","siteChange","createdAt","updatedAt"],"additionalProperties":false,"description":"A spot as list_spots returns it.","x-group":"Objects"},"SpotDetail":{"type":"object","properties":{"spotId":{"type":"string","x-sceniq-id":"spots","description":"The spot's id."},"spotKey":{"type":"string","description":"The spot's stable key within the guide; chapters and routes reference spots by it."},"productId":{"type":"string","x-sceniq-id":"products","description":"The guide the spot belongs to."},"title":{"type":"string","description":"The place name."},"kicker":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The short line above the title (region or type)."},"lat":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Latitude in decimal degrees, or null when the pin is not set yet."},"lon":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Longitude in decimal degrees, or null when the pin is not set yet."},"mapsUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The creator's own map link."},"shortDescription":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"One or two sentences for the card."},"longDescription":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The full write-up."},"color":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Pin color as a hex value, or null for the default."},"cardOrientation":{"enum":["portrait","landscape"],"description":"Photo framing in the viewer."},"customValues":{"type":"object","additionalProperties":{},"description":"Custom property values keyed by property key; option values are option ids."},"tripFacts":{"anyOf":[{"$ref":"#/components/schemas/TripFacts"},{"type":"null"}],"description":"The planning stats bar."},"arrival":{"anyOf":[{"$ref":"#/components/schemas/Arrival"},{"type":"null"}],"description":"How to get there."},"mapLinks":{"type":"array","items":{"$ref":"#/components/schemas/MapLink"},"description":"Extra map links, drawn as map pills."},"imagesEnabled":{"type":"boolean","description":"false hides the photo section from buyers."},"customPropsEnabled":{"type":"boolean","description":"false hides the custom properties from buyers."},"archived":{"type":"boolean","description":"true when the spot is hidden from buyers but kept."},"ref":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Your own stable key for upsert_spots."},"accessMode":{"anyOf":[{"enum":["drive_up","short_walk","hike","multi_day","boat","cable_car","train","flight","tour_only","aerial_only"]},{"type":"null"}],"description":"How visitors reach the spot, shown as Accessibility."},"pinLabel":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"What the main pin marks, for a spot that is an area or a line."},"pins":{"type":"array","items":{"$ref":"#/components/schemas/SpotPin"},"description":"Extra points: viewpoints, entrances, trailheads, parking."},"links":{"type":"array","items":{"$ref":"#/components/schemas/GuideLink"},"description":"Links with a purpose."},"status":{"anyOf":[{"$ref":"#/components/schemas/StatusNotice"},{"type":"null"}],"description":"A closure or works notice."},"fees":{"type":"array","items":{"$ref":"#/components/schemas/Fee"},"description":"Fees and tickets."},"schedule":{"anyOf":[{"$ref":"#/components/schemas/Schedule"},{"type":"null"}],"description":"Structured opening hours."},"features":{"type":"array","items":{"$ref":"#/components/schemas/SpotFeature"},"description":"Parts of the site with their own rules."},"restrictions":{"type":"array","items":{"$ref":"#/components/schemas/Restriction"},"description":"Rules on site."},"events":{"type":"array","items":{"$ref":"#/components/schemas/SpotEvent"},"description":"Events worth timing a visit for."},"food":{"anyOf":[{"$ref":"#/components/schemas/FoodNote"},{"type":"null"}],"description":"Why the spot lists no food places."},"areaId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The area (park, island, region) the spot sits in."},"timeZone":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"IANA time zone, derived from the pin unless set by hand."},"timeZoneManual":{"type":"boolean","description":"true when the time zone was set by hand rather than from the pin."},"customNotes":{"type":"object","additionalProperties":{"type":"string"},"description":"One short note per custom property value, keyed by property key."},"sources":{"type":"array","items":{"$ref":"#/components/schemas/SourceRef"},"description":"Research evidence for the review, never shown to buyers."},"reviewNotes":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Notes for the creator's review, never shown to buyers."},"factsCheckedOn":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The day the facts were last checked (YYYY-MM-DD)."},"reviewBy":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The day the facts need a new check (YYYY-MM-DD)."},"siteChange":{"anyOf":[{"$ref":"#/components/schemas/SiteChange"},{"type":"null"}],"description":"The day something at the spot changed."},"createdAt":{"type":"number","description":"When the row was created (Unix time in milliseconds)."},"updatedAt":{"type":"number","description":"When the row last changed (Unix time in milliseconds)."},"photos":{"type":"array","items":{"type":"object","properties":{"mediaId":{"type":"string","x-sceniq-id":"media","description":"The photo's id."},"url":{"type":"string","description":"The photo's URL."},"caption":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Caption."},"credit":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Photographer credit."},"width":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Width in pixels."},"height":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Height in pixels."},"order":{"type":"number","description":"Position in the spot's gallery (ascending)."}},"required":["mediaId","url","caption","credit","width","height","order"],"additionalProperties":false},"description":"The spot's photos in gallery order. list_media has every photo field."},"chapters":{"type":"array","items":{"type":"object","properties":{"collectionId":{"type":"string","x-sceniq-id":"collections","description":"The chapter's or collection's id."},"name":{"type":"string","description":"Its name."},"kind":{"enum":["collection","chapter"],"description":"chapter carries prose; collection is a plain spot set."},"order":{"type":"number","description":"The spot's position inside that chapter."}},"required":["collectionId","name","kind","order"],"additionalProperties":false},"description":"The chapters and collections the spot belongs to."},"routes":{"type":"array","items":{"type":"object","properties":{"routeId":{"type":"string","x-sceniq-id":"routes","description":"The route's id."},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The route's name."},"order":{"type":"number","description":"The spot's position on the route."},"quickest":{"type":"boolean","description":"true when this route is the fastest approach to the spot."}},"required":["routeId","name","order","quickest"],"additionalProperties":false},"description":"The routes that reach the spot."}},"required":["spotId","spotKey","productId","title","kicker","lat","lon","mapsUrl","shortDescription","longDescription","color","cardOrientation","customValues","tripFacts","arrival","mapLinks","imagesEnabled","customPropsEnabled","archived","ref","accessMode","pinLabel","pins","links","status","fees","schedule","features","restrictions","events","food","areaId","timeZone","timeZoneManual","customNotes","sources","reviewNotes","factsCheckedOn","reviewBy","siteChange","createdAt","updatedAt","photos","chapters","routes"],"additionalProperties":false,"description":"A spot with its photos, chapters and routes (get_spot).","x-group":"Objects"},"SpotWrite":{"type":"object","properties":{"spotId":{"type":"string","x-sceniq-id":"spots","description":"The spot's id."},"spotKey":{"type":"string","description":"The spot's stable key within the guide; chapters and routes reference spots by it."},"productId":{"type":"string","x-sceniq-id":"products","description":"The guide the spot belongs to."},"title":{"type":"string","description":"The place name."},"kicker":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The short line above the title (region or type)."},"lat":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Latitude in decimal degrees, or null when the pin is not set yet."},"lon":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Longitude in decimal degrees, or null when the pin is not set yet."},"mapsUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The creator's own map link."},"shortDescription":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"One or two sentences for the card."},"longDescription":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The full write-up."},"color":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Pin color as a hex value, or null for the default."},"cardOrientation":{"enum":["portrait","landscape"],"description":"Photo framing in the viewer."},"customValues":{"type":"object","additionalProperties":{},"description":"Custom property values keyed by property key; option values are option ids."},"tripFacts":{"anyOf":[{"$ref":"#/components/schemas/TripFacts"},{"type":"null"}],"description":"The planning stats bar."},"arrival":{"anyOf":[{"$ref":"#/components/schemas/Arrival"},{"type":"null"}],"description":"How to get there."},"mapLinks":{"type":"array","items":{"$ref":"#/components/schemas/MapLink"},"description":"Extra map links, drawn as map pills."},"imagesEnabled":{"type":"boolean","description":"false hides the photo section from buyers."},"customPropsEnabled":{"type":"boolean","description":"false hides the custom properties from buyers."},"archived":{"type":"boolean","description":"true when the spot is hidden from buyers but kept."},"ref":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Your own stable key for upsert_spots."},"accessMode":{"anyOf":[{"enum":["drive_up","short_walk","hike","multi_day","boat","cable_car","train","flight","tour_only","aerial_only"]},{"type":"null"}],"description":"How visitors reach the spot, shown as Accessibility."},"pinLabel":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"What the main pin marks, for a spot that is an area or a line."},"pins":{"type":"array","items":{"$ref":"#/components/schemas/SpotPin"},"description":"Extra points: viewpoints, entrances, trailheads, parking."},"links":{"type":"array","items":{"$ref":"#/components/schemas/GuideLink"},"description":"Links with a purpose."},"status":{"anyOf":[{"$ref":"#/components/schemas/StatusNotice"},{"type":"null"}],"description":"A closure or works notice."},"fees":{"type":"array","items":{"$ref":"#/components/schemas/Fee"},"description":"Fees and tickets."},"schedule":{"anyOf":[{"$ref":"#/components/schemas/Schedule"},{"type":"null"}],"description":"Structured opening hours."},"features":{"type":"array","items":{"$ref":"#/components/schemas/SpotFeature"},"description":"Parts of the site with their own rules."},"restrictions":{"type":"array","items":{"$ref":"#/components/schemas/Restriction"},"description":"Rules on site."},"events":{"type":"array","items":{"$ref":"#/components/schemas/SpotEvent"},"description":"Events worth timing a visit for."},"food":{"anyOf":[{"$ref":"#/components/schemas/FoodNote"},{"type":"null"}],"description":"Why the spot lists no food places."},"areaId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The area (park, island, region) the spot sits in."},"timeZone":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"IANA time zone, derived from the pin unless set by hand."},"timeZoneManual":{"type":"boolean","description":"true when the time zone was set by hand rather than from the pin."},"customNotes":{"type":"object","additionalProperties":{"type":"string"},"description":"One short note per custom property value, keyed by property key."},"sources":{"type":"array","items":{"$ref":"#/components/schemas/SourceRef"},"description":"Research evidence for the review, never shown to buyers."},"reviewNotes":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Notes for the creator's review, never shown to buyers."},"factsCheckedOn":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The day the facts were last checked (YYYY-MM-DD)."},"reviewBy":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The day the facts need a new check (YYYY-MM-DD)."},"siteChange":{"anyOf":[{"$ref":"#/components/schemas/SiteChange"},{"type":"null"}],"description":"The day something at the spot changed."},"createdAt":{"type":"number","description":"When the row was created (Unix time in milliseconds)."},"updatedAt":{"type":"number","description":"When the row last changed (Unix time in milliseconds)."},"photos":{"type":"array","items":{"type":"object","properties":{"mediaId":{"type":"string","x-sceniq-id":"media","description":"The photo's id."},"url":{"type":"string","description":"The photo's URL."},"caption":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Caption."},"credit":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Photographer credit."},"width":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Width in pixels."},"height":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Height in pixels."},"order":{"type":"number","description":"Position in the spot's gallery (ascending)."}},"required":["mediaId","url","caption","credit","width","height","order"],"additionalProperties":false},"description":"The spot's photos in gallery order. list_media has every photo field."},"chapters":{"type":"array","items":{"type":"object","properties":{"collectionId":{"type":"string","x-sceniq-id":"collections","description":"The chapter's or collection's id."},"name":{"type":"string","description":"Its name."},"kind":{"enum":["collection","chapter"],"description":"chapter carries prose; collection is a plain spot set."},"order":{"type":"number","description":"The spot's position inside that chapter."}},"required":["collectionId","name","kind","order"],"additionalProperties":false},"description":"The chapters and collections the spot belongs to."},"routes":{"type":"array","items":{"type":"object","properties":{"routeId":{"type":"string","x-sceniq-id":"routes","description":"The route's id."},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The route's name."},"order":{"type":"number","description":"The spot's position on the route."},"quickest":{"type":"boolean","description":"true when this route is the fastest approach to the spot."}},"required":["routeId","name","order","quickest"],"additionalProperties":false},"description":"The routes that reach the spot."},"warnings":{"type":"array","items":{"type":"string"},"description":"Notes about things the write accepted but you should look at (a plain http link). Present only when there are any."}},"required":["spotId","spotKey","productId","title","kicker","lat","lon","mapsUrl","shortDescription","longDescription","color","cardOrientation","customValues","tripFacts","arrival","mapLinks","imagesEnabled","customPropsEnabled","archived","ref","accessMode","pinLabel","pins","links","status","fees","schedule","features","restrictions","events","food","areaId","timeZone","timeZoneManual","customNotes","sources","reviewNotes","factsCheckedOn","reviewBy","siteChange","createdAt","updatedAt","photos","chapters","routes"],"additionalProperties":false,"description":"A spot after create_spot or update_spot, with the write's warnings.","x-group":"Objects"},"Property":{"type":"object","properties":{"propertyDefId":{"type":"string","x-sceniq-id":"propertyDefs","description":"The property's id."},"key":{"type":"string","description":"The immutable key spots use in customValues."},"label":{"type":"string","description":"The label buyers see."},"kind":{"enum":["shortLabel","longSection","number","date","checkbox","singleSelect"],"description":"The kind; it decides the value's type and whether buyers can filter by it."},"order":{"type":"number","description":"Display order (ascending)."},"required":{"type":"boolean","description":"true when every spot must carry a value. Absent means false."},"filterable":{"type":"boolean","description":"Whether buyers can filter by it (number, date, checkbox and singleSelect)."},"placeholder":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Editor placeholder text."},"numUnit":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Unit label for number properties."},"options":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The option's immutable id: the value spots store."},"label":{"type":"string","description":"The option's label."},"order":{"type":"number","description":"Display order (ascending)."},"archived":{"type":"boolean","description":"true when the option is retired; stored values stay."}},"required":["id","label","order","archived"],"additionalProperties":false},"description":"Options of checkbox and singleSelect properties."},"archived":{"type":"boolean","description":"true when the property is archived; stored values stay."},"schemaVersion":{"type":"number","description":"The guide's property schema version after the last change."}},"required":["propertyDefId","key","label","kind","order","filterable","placeholder","numUnit","options","archived","schemaVersion"],"additionalProperties":false,"description":"A custom property definition.","x-group":"Objects"},"Guide":{"type":"object","properties":{"productId":{"type":"string","x-sceniq-id":"products","description":"The guide's id."},"name":{"type":"string","description":"The guide's title."},"slug":{"type":"string","description":"URL slug of the sales page."},"headline":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"One-line promise under the title on the sales page."},"purchaseButtonText":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The buy button label, or null for the default."},"status":{"enum":["draft","published","archived"],"description":"draft (not on sale), published (on sale) or archived."},"visibleOnStore":{"type":"boolean","description":"Whether the guide shows in the Sceniq store (set in the studio)."},"storeReviewStatus":{"anyOf":[{"enum":["pending","approved","rejected"]},{"type":"null"}],"description":"The store review's state, or null before a review."},"storeReviewNote":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The store review team's note."},"storeTags":{"type":"array","items":{"type":"string"},"description":"Store tags from the fixed vocabulary."},"country":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"ISO 3166-1 alpha-2 code of the country the guide covers; null means worldwide."},"reviewsShown":{"type":"boolean","description":"Whether buyer reviews show on the store card."},"buyerCountShown":{"type":"boolean","description":"Whether the buyer count shows on the sales page (set in the studio)."},"pricing":{"type":"object","properties":{"oneTimeEnabled":{"type":"boolean","description":"Whether the guide sells for a one-time price."},"subscriptionIncluded":{"type":"boolean","description":"Whether it is part of a subscription."},"currency":{"type":"string","description":"The guide's currency."}},"required":["oneTimeEnabled","subscriptionIncluded","currency"],"additionalProperties":false,"description":"How the guide is sold."},"originalLanguage":{"type":"string","description":"The language the guide is written in (BCP 47)."},"createdAt":{"type":"number","description":"When the row was created (Unix time in milliseconds)."},"updatedAt":{"type":"number","description":"When the row last changed (Unix time in milliseconds)."},"publishedAt":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"When the guide first went on sale (Unix time in milliseconds)."},"lastApiWriteAt":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"When a key last changed the guide (Unix time in milliseconds)."},"region":{"anyOf":[{"$ref":"#/components/schemas/MapRegion"},{"type":"null"}],"description":"The map region the viewer opens on."},"areas":{"type":"array","items":{"$ref":"#/components/schemas/Area"},"description":"Parks, islands and regions spots can point at."},"mapStyle":{"anyOf":[{"type":"object","properties":{"basemap":{"type":"string","description":"The base map style."},"pinStyle":{"type":"string","description":"The pin style."},"themeColor":{"type":"string","description":"The accent color."}},"additionalProperties":false},{"type":"null"}],"description":"The map's style, set in the studio."},"propertySchemaVersion":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Bumped on every property change."},"properties":{"type":"array","items":{"$ref":"#/components/schemas/Property"},"description":"Custom property definitions."},"price":{"anyOf":[{"type":"object","properties":{"amountMinor":{"type":"number","description":"The price in minor units (2900 is 29.00)."},"currency":{"type":"string","description":"ISO 4217 code in lower case (usd, eur, chf)."}},"required":["amountMinor","currency"],"additionalProperties":false},{"type":"null"}],"description":"The active one-time price, or null when none is set."},"spotCount":{"type":"number","description":"Number of spots, archived ones included."},"thumbnailUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The 4:5 store thumbnail."},"dashboardUrl":{"type":"string","description":"The guide in the studio."},"salesPageUrl":{"type":"string","description":"The public sales page (live once published)."}},"required":["productId","name","slug","headline","purchaseButtonText","status","visibleOnStore","storeReviewStatus","storeReviewNote","storeTags","country","reviewsShown","buyerCountShown","pricing","originalLanguage","createdAt","updatedAt","publishedAt","lastApiWriteAt","region","areas","mapStyle","propertySchemaVersion","properties","price","spotCount","thumbnailUrl","dashboardUrl","salesPageUrl"],"additionalProperties":false,"description":"A guide: settings, region, areas, properties and price.","x-group":"Objects"},"GuideDetail":{"type":"object","properties":{"productId":{"type":"string","x-sceniq-id":"products","description":"The guide's id."},"name":{"type":"string","description":"The guide's title."},"slug":{"type":"string","description":"URL slug of the sales page."},"headline":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"One-line promise under the title on the sales page."},"purchaseButtonText":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The buy button label, or null for the default."},"status":{"enum":["draft","published","archived"],"description":"draft (not on sale), published (on sale) or archived."},"visibleOnStore":{"type":"boolean","description":"Whether the guide shows in the Sceniq store (set in the studio)."},"storeReviewStatus":{"anyOf":[{"enum":["pending","approved","rejected"]},{"type":"null"}],"description":"The store review's state, or null before a review."},"storeReviewNote":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The store review team's note."},"storeTags":{"type":"array","items":{"type":"string"},"description":"Store tags from the fixed vocabulary."},"country":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"ISO 3166-1 alpha-2 code of the country the guide covers; null means worldwide."},"reviewsShown":{"type":"boolean","description":"Whether buyer reviews show on the store card."},"buyerCountShown":{"type":"boolean","description":"Whether the buyer count shows on the sales page (set in the studio)."},"pricing":{"type":"object","properties":{"oneTimeEnabled":{"type":"boolean","description":"Whether the guide sells for a one-time price."},"subscriptionIncluded":{"type":"boolean","description":"Whether it is part of a subscription."},"currency":{"type":"string","description":"The guide's currency."}},"required":["oneTimeEnabled","subscriptionIncluded","currency"],"additionalProperties":false,"description":"How the guide is sold."},"originalLanguage":{"type":"string","description":"The language the guide is written in (BCP 47)."},"createdAt":{"type":"number","description":"When the row was created (Unix time in milliseconds)."},"updatedAt":{"type":"number","description":"When the row last changed (Unix time in milliseconds)."},"publishedAt":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"When the guide first went on sale (Unix time in milliseconds)."},"lastApiWriteAt":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"When a key last changed the guide (Unix time in milliseconds)."},"region":{"anyOf":[{"$ref":"#/components/schemas/MapRegion"},{"type":"null"}],"description":"The map region the viewer opens on."},"areas":{"type":"array","items":{"$ref":"#/components/schemas/Area"},"description":"Parks, islands and regions spots can point at."},"mapStyle":{"anyOf":[{"type":"object","properties":{"basemap":{"type":"string","description":"The base map style."},"pinStyle":{"type":"string","description":"The pin style."},"themeColor":{"type":"string","description":"The accent color."}},"additionalProperties":false},{"type":"null"}],"description":"The map's style, set in the studio."},"propertySchemaVersion":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Bumped on every property change."},"properties":{"type":"array","items":{"$ref":"#/components/schemas/Property"},"description":"Custom property definitions."},"price":{"anyOf":[{"type":"object","properties":{"amountMinor":{"type":"number","description":"The price in minor units (2900 is 29.00)."},"currency":{"type":"string","description":"ISO 4217 code in lower case (usd, eur, chf)."}},"required":["amountMinor","currency"],"additionalProperties":false},{"type":"null"}],"description":"The active one-time price, or null when none is set."},"spotCount":{"type":"number","description":"Number of spots, archived ones included."},"thumbnailUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The 4:5 store thumbnail."},"dashboardUrl":{"type":"string","description":"The guide in the studio."},"salesPageUrl":{"type":"string","description":"The public sales page (live once published)."},"chapterCount":{"type":"number","description":"Number of chapters and collections."},"photoCount":{"type":"number","description":"Number of photos across the guide."}},"required":["productId","name","slug","headline","purchaseButtonText","status","visibleOnStore","storeReviewStatus","storeReviewNote","storeTags","country","reviewsShown","buyerCountShown","pricing","originalLanguage","createdAt","updatedAt","publishedAt","lastApiWriteAt","region","areas","mapStyle","propertySchemaVersion","properties","price","spotCount","thumbnailUrl","dashboardUrl","salesPageUrl","chapterCount","photoCount"],"additionalProperties":false,"description":"A guide with its chapter and photo counts (get_guide).","x-group":"Objects"},"GuideSummary":{"type":"object","properties":{"productId":{"type":"string","x-sceniq-id":"products","description":"The guide's id."},"name":{"type":"string","description":"The guide's title."},"slug":{"type":"string","description":"URL slug of the sales page."},"headline":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"One-line promise under the title."},"status":{"enum":["draft","published","archived"],"description":"draft, published or archived."},"visibleOnStore":{"type":"boolean","description":"Whether the guide shows in the store."},"storeReviewStatus":{"anyOf":[{"enum":["pending","approved","rejected"]},{"type":"null"}],"description":"The store review's state."},"storeTags":{"type":"array","items":{"type":"string"},"description":"Store tags."},"country":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Country code, or null for worldwide."},"price":{"anyOf":[{"type":"object","properties":{"amountMinor":{"type":"number","description":"The price in minor units (2900 is 29.00)."},"currency":{"type":"string","description":"ISO 4217 code in lower case (usd, eur, chf)."}},"required":["amountMinor","currency"],"additionalProperties":false},{"type":"null"}],"description":"The active one-time price."},"buyers":{"type":"number","description":"How many people own the guide."},"createdAt":{"type":"number","description":"When the row was created (Unix time in milliseconds)."},"updatedAt":{"type":"number","description":"When the row last changed (Unix time in milliseconds)."},"publishedAt":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"When the guide first went on sale."},"dashboardUrl":{"type":"string","description":"The guide in the studio."},"salesPageUrl":{"type":"string","description":"The public sales page."}},"required":["productId","name","slug","headline","status","visibleOnStore","storeReviewStatus","storeTags","country","price","buyers","createdAt","updatedAt","publishedAt","dashboardUrl","salesPageUrl"],"additionalProperties":false,"description":"One row of list_guides.","x-group":"Objects"},"AreaWithSpots":{"type":"object","properties":{"id":{"type":"string","description":"The area's id."},"name":{"type":"string","description":"The area's name."},"kind":{"enum":["park","reserve","island","region","city","other"],"description":"park, reserve, island, region, city or other."},"note":{"type":"string","description":"What applies across the area."},"season":{"type":"string","description":"The area's season in words."},"rules":{"type":"array","items":{"$ref":"#/components/schemas/AccessRule"},"description":"Access rules for the whole area."},"fees":{"type":"array","items":{"$ref":"#/components/schemas/Fee"},"description":"Fees for the whole area."},"links":{"type":"array","items":{"$ref":"#/components/schemas/GuideLink"},"description":"Links for the whole area."},"status":{"$ref":"#/components/schemas/StatusNotice","description":"A closure notice for the whole area."},"sources":{"type":"array","items":{"$ref":"#/components/schemas/SourceRef"},"description":"Research evidence, never shown to buyers."},"spotKeys":{"type":"array","items":{"type":"string"},"description":"The spots that point at the area (update_spot areaId)."}},"required":["id","name","spotKeys"],"additionalProperties":false,"description":"An area with the spots that point at it.","x-group":"Objects"},"Chapter":{"type":"object","properties":{"collectionId":{"type":"string","x-sceniq-id":"collections","description":"The chapter's or collection's id."},"productId":{"type":"string","x-sceniq-id":"products","description":"The guide's id."},"name":{"type":"string","description":"Its title."},"slug":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"URL slug, unique in the guide."},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"One-line summary on the chapter card."},"kind":{"enum":["collection","chapter"],"description":"chapter carries prose and front matter; collection is a plain spot set."},"body":{"type":"array","items":{"type":"string"},"description":"Prose paragraphs (chapters only)."},"intro":{"anyOf":[{"$ref":"#/components/schemas/ChapterIntro"},{"type":"null"}],"description":"Structured front matter (chapters only)."},"order":{"type":"number","description":"Position in the guide."},"coverUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The cover image."},"coverStorageId":{"anyOf":[{"type":"string","x-sceniq-id":"_storage"},{"type":"null"}],"description":"The cover's storage id (from an upload with target=blob)."},"members":{"type":"array","items":{"type":"object","properties":{"spotKey":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"A member spot's key."},"memberCollectionId":{"anyOf":[{"type":"string","x-sceniq-id":"collections"},{"type":"null"}],"description":"A chapter placed as a card inside a collection."},"order":{"type":"number","description":"Position in the chapter."}},"required":["spotKey","memberCollectionId","order"],"additionalProperties":false},"description":"Members in order: spots, or chapters inside a collection."},"createdAt":{"type":"number","description":"When the row was created (Unix time in milliseconds)."},"updatedAt":{"type":"number","description":"When the row last changed (Unix time in milliseconds)."}},"required":["collectionId","productId","name","slug","description","kind","body","intro","order","coverUrl","coverStorageId","members","createdAt","updatedAt"],"additionalProperties":false,"description":"A chapter or a collection with its members.","x-group":"Objects"},"Route":{"type":"object","properties":{"routeId":{"type":"string","x-sceniq-id":"routes","description":"The route's id."},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The route's name."},"activity":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"hike, walk, bike, drive, ski or paddle; null means hike."},"sacGrade":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The grade as written in gradeScale."},"gradeScale":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"sac, via_ferrata, cai, yds, mtb, whitewater or other; null means sac."},"effortLabel":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Easy, Moderate, Hard (free text)."},"durationMin":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Duration in minutes (see durationBasis)."},"gainM":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Elevation gain in meters."},"descentM":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Descent in meters."},"distanceKm":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Distance in kilometers."},"start":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The trailhead in words."},"startMapsUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Map link to the trailhead."},"transit":{"type":"array","items":{"$ref":"#/components/schemas/TransitNote"},"description":"Transit notes per mode."},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The route in the creator's words."},"equipment":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"description":"Gear; [] means explicitly none, null means unknown."},"sources":{"type":"array","items":{"type":"string"},"description":"Where the facts come from."},"extraProps":{"type":"array","items":{"$ref":"#/components/schemas/ExtraProp"},"description":"Free label and value rows."},"track":{"anyOf":[{"$ref":"#/components/schemas/RouteTrack"},{"type":"null"}],"description":"The route line."},"status":{"anyOf":[{"$ref":"#/components/schemas/StatusNotice"},{"type":"null"}],"description":"A closure notice."},"season":{"anyOf":[{"$ref":"#/components/schemas/RouteSeason"},{"type":"null"}],"description":"When the route can be walked."},"variants":{"type":"array","items":{"$ref":"#/components/schemas/RouteVariant"},"description":"Alternatives."},"stages":{"type":"array","items":{"$ref":"#/components/schemas/RouteStage"},"description":"Days or legs of a trek."},"segments":{"type":"array","items":{"$ref":"#/components/schemas/RouteSegment"},"description":"Sections with their own access."},"shape":{"anyOf":[{"enum":["loop","out_and_back","one_way"]},{"type":"null"}],"description":"loop, out_and_back or one_way."},"durationBasis":{"anyOf":[{"enum":["round_trip","one_way","ascent"]},{"type":"null"}],"description":"What durationMin counts: round_trip, one_way or ascent."},"ascentMin":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Minutes up."},"descentMin":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Minutes down."},"sourceGrade":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The source's own grade."},"figureSources":{"type":"array","items":{"$ref":"#/components/schemas/FigureSource"},"description":"Where each number comes from."},"reviewNotes":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Notes for the creator's review, never shown to buyers."},"factsCheckedOn":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The day the facts were last checked (YYYY-MM-DD)."},"reviewBy":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The day the facts need a new check (YYYY-MM-DD)."},"createdAt":{"type":"number","description":"When the row was created (Unix time in milliseconds)."},"updatedAt":{"type":"number","description":"When the row last changed (Unix time in milliseconds)."},"spots":{"type":"array","items":{"type":"object","properties":{"spotKey":{"type":"string","description":"The spot's key."},"order":{"type":"number","description":"Position on the route."},"quickest":{"type":"boolean","description":"true when this is the fastest approach to the spot."},"role":{"enum":["required","optional"],"description":"required: the way in. optional: a walk from the spot that never sets its Accessibility."}},"required":["spotKey","order","quickest","role"],"additionalProperties":false},"description":"The spots the route passes, in order."},"facilities":{"type":"array","items":{"type":"object","properties":{"facilityId":{"type":"string","x-sceniq-id":"facilities","description":"The place's id."},"order":{"type":"number","description":"Position on the route."}},"required":["facilityId","order"],"additionalProperties":false},"description":"The places the route uses, in order."}},"required":["routeId","name","activity","sacGrade","gradeScale","effortLabel","durationMin","gainM","descentM","distanceKm","start","startMapsUrl","transit","description","equipment","sources","extraProps","track","status","season","variants","stages","segments","shape","durationBasis","ascentMin","descentMin","sourceGrade","figureSources","reviewNotes","factsCheckedOn","reviewBy","createdAt","updatedAt","spots","facilities"],"additionalProperties":false,"description":"A route with its facts and its spot and place links.","x-group":"Objects"},"RouteWrite":{"type":"object","properties":{"routeId":{"type":"string","x-sceniq-id":"routes","description":"The route's id."},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The route's name."},"activity":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"hike, walk, bike, drive, ski or paddle; null means hike."},"sacGrade":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The grade as written in gradeScale."},"gradeScale":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"sac, via_ferrata, cai, yds, mtb, whitewater or other; null means sac."},"effortLabel":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Easy, Moderate, Hard (free text)."},"durationMin":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Duration in minutes (see durationBasis)."},"gainM":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Elevation gain in meters."},"descentM":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Descent in meters."},"distanceKm":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Distance in kilometers."},"start":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The trailhead in words."},"startMapsUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Map link to the trailhead."},"transit":{"type":"array","items":{"$ref":"#/components/schemas/TransitNote"},"description":"Transit notes per mode."},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The route in the creator's words."},"equipment":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"description":"Gear; [] means explicitly none, null means unknown."},"sources":{"type":"array","items":{"type":"string"},"description":"Where the facts come from."},"extraProps":{"type":"array","items":{"$ref":"#/components/schemas/ExtraProp"},"description":"Free label and value rows."},"track":{"anyOf":[{"$ref":"#/components/schemas/RouteTrack"},{"type":"null"}],"description":"The route line."},"status":{"anyOf":[{"$ref":"#/components/schemas/StatusNotice"},{"type":"null"}],"description":"A closure notice."},"season":{"anyOf":[{"$ref":"#/components/schemas/RouteSeason"},{"type":"null"}],"description":"When the route can be walked."},"variants":{"type":"array","items":{"$ref":"#/components/schemas/RouteVariant"},"description":"Alternatives."},"stages":{"type":"array","items":{"$ref":"#/components/schemas/RouteStage"},"description":"Days or legs of a trek."},"segments":{"type":"array","items":{"$ref":"#/components/schemas/RouteSegment"},"description":"Sections with their own access."},"shape":{"anyOf":[{"enum":["loop","out_and_back","one_way"]},{"type":"null"}],"description":"loop, out_and_back or one_way."},"durationBasis":{"anyOf":[{"enum":["round_trip","one_way","ascent"]},{"type":"null"}],"description":"What durationMin counts: round_trip, one_way or ascent."},"ascentMin":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Minutes up."},"descentMin":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Minutes down."},"sourceGrade":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The source's own grade."},"figureSources":{"type":"array","items":{"$ref":"#/components/schemas/FigureSource"},"description":"Where each number comes from."},"reviewNotes":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Notes for the creator's review, never shown to buyers."},"factsCheckedOn":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The day the facts were last checked (YYYY-MM-DD)."},"reviewBy":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The day the facts need a new check (YYYY-MM-DD)."},"createdAt":{"type":"number","description":"When the row was created (Unix time in milliseconds)."},"updatedAt":{"type":"number","description":"When the row last changed (Unix time in milliseconds)."},"spots":{"type":"array","items":{"type":"object","properties":{"spotKey":{"type":"string","description":"The spot's key."},"order":{"type":"number","description":"Position on the route."},"quickest":{"type":"boolean","description":"true when this is the fastest approach to the spot."},"role":{"enum":["required","optional"],"description":"required: the way in. optional: a walk from the spot that never sets its Accessibility."}},"required":["spotKey","order","quickest","role"],"additionalProperties":false},"description":"The spots the route passes, in order."},"facilities":{"type":"array","items":{"type":"object","properties":{"facilityId":{"type":"string","x-sceniq-id":"facilities","description":"The place's id."},"order":{"type":"number","description":"Position on the route."}},"required":["facilityId","order"],"additionalProperties":false},"description":"The places the route uses, in order."},"warnings":{"type":"array","items":{"type":"string"},"description":"Notes about things the write accepted but you should look at (a plain http link). Present only when there are any."}},"required":["routeId","name","activity","sacGrade","gradeScale","effortLabel","durationMin","gainM","descentM","distanceKm","start","startMapsUrl","transit","description","equipment","sources","extraProps","track","status","season","variants","stages","segments","shape","durationBasis","ascentMin","descentMin","sourceGrade","figureSources","reviewNotes","factsCheckedOn","reviewBy","createdAt","updatedAt","spots","facilities"],"additionalProperties":false,"description":"A route after create_route, with the write's warnings.","x-group":"Objects"},"Place":{"type":"object","properties":{"facilityId":{"type":"string","x-sceniq-id":"facilities","description":"The place's id."},"kind":{"enum":["hut","cable_car","activity","food","parking"],"description":"hut (a stay), cable_car (transport), activity (tours), food or parking."},"type":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The sub-type (hotel, ferry, restaurant ...), or null for the kind's default."},"spotKeys":{"type":"array","items":{"type":"string"},"description":"The spots it serves directly, in order."},"name":{"type":"string","description":"The place's name."},"operator":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Who runs it."},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The place in the creator's words."},"costRaw":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The price as the creator states it."},"openRaw":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Season or hours as text."},"website":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The official site."},"mapsUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Map link."},"extraProps":{"type":"array","items":{"$ref":"#/components/schemas/ExtraProp"},"description":"Free label and value rows."},"lat":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"The place's own latitude."},"lon":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"The place's own longitude."},"osmId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"OpenStreetMap reference."},"googlePlaceId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Google place id."},"country":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"ISO 3166-1 alpha-2 code."},"timeZone":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"IANA time zone, from the pin."},"links":{"type":"array","items":{"$ref":"#/components/schemas/GuideLink"},"description":"Links with a purpose."},"bookingRequired":{"type":"boolean","description":"true shows Booking required."},"bookingUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The page to book on."},"extraKinds":{"type":"array","items":{"enum":["hut","cable_car","activity","food","parking"]},"description":"Further roles of the same place."},"insideId":{"anyOf":[{"type":"string","x-sceniq-id":"facilities"},{"type":"null"}],"description":"The place this one sits inside."},"needsParentTicket":{"type":"boolean","description":"true when entering needs the parent place's ticket."},"conditions":{"anyOf":[{"$ref":"#/components/schemas/PlaceConditions"},{"type":"null"}],"description":"Conditions shown as chips."},"costUnit":{"anyOf":[{"enum":["per_person","per_night","per_person_night","per_room","per_vehicle","per_trip","per_hour","per_day"]},{"type":"null"}],"description":"What costRaw counts."},"parking":{"anyOf":[{"$ref":"#/components/schemas/ParkingInfo"},{"type":"null"}],"description":"Parking details."},"transport":{"anyOf":[{"$ref":"#/components/schemas/TransportInfo"},{"type":"null"}],"description":"Transport details."},"activity":{"anyOf":[{"$ref":"#/components/schemas/ActivityInfo"},{"type":"null"}],"description":"Tour and activity details."},"gatewayTown":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The town the place sits in when it is far from the spot on purpose."},"status":{"anyOf":[{"$ref":"#/components/schemas/StatusNotice"},{"type":"null"}],"description":"A closure notice."},"fees":{"type":"array","items":{"$ref":"#/components/schemas/Fee"},"description":"Fees and tickets."},"schedule":{"anyOf":[{"$ref":"#/components/schemas/Schedule"},{"type":"null"}],"description":"Structured opening hours."},"sources":{"type":"array","items":{"$ref":"#/components/schemas/SourceRef"},"description":"Research evidence, never shown to buyers."},"reviewNotes":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Notes for the creator's review, never shown to buyers."},"factsCheckedOn":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The day the facts were last checked (YYYY-MM-DD)."},"reviewBy":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The day the facts need a new check (YYYY-MM-DD)."},"createdAt":{"type":"number","description":"When the row was created (Unix time in milliseconds)."},"updatedAt":{"type":"number","description":"When the row last changed (Unix time in milliseconds)."}},"required":["facilityId","kind","type","spotKeys","name","operator","description","costRaw","openRaw","website","mapsUrl","extraProps","lat","lon","osmId","googlePlaceId","country","timeZone","links","bookingRequired","bookingUrl","extraKinds","insideId","needsParentTicket","conditions","costUnit","parking","transport","activity","gatewayTown","status","fees","schedule","sources","reviewNotes","factsCheckedOn","reviewBy","createdAt","updatedAt"],"additionalProperties":false,"description":"A place: a stay, transport, a tour, food or parking.","x-group":"Objects"},"PlaceWrite":{"type":"object","properties":{"facilityId":{"type":"string","x-sceniq-id":"facilities","description":"The place's id."},"kind":{"enum":["hut","cable_car","activity","food","parking"],"description":"hut (a stay), cable_car (transport), activity (tours), food or parking."},"type":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The sub-type (hotel, ferry, restaurant ...), or null for the kind's default."},"spotKeys":{"type":"array","items":{"type":"string"},"description":"The spots it serves directly, in order."},"name":{"type":"string","description":"The place's name."},"operator":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Who runs it."},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The place in the creator's words."},"costRaw":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The price as the creator states it."},"openRaw":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Season or hours as text."},"website":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The official site."},"mapsUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Map link."},"extraProps":{"type":"array","items":{"$ref":"#/components/schemas/ExtraProp"},"description":"Free label and value rows."},"lat":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"The place's own latitude."},"lon":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"The place's own longitude."},"osmId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"OpenStreetMap reference."},"googlePlaceId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Google place id."},"country":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"ISO 3166-1 alpha-2 code."},"timeZone":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"IANA time zone, from the pin."},"links":{"type":"array","items":{"$ref":"#/components/schemas/GuideLink"},"description":"Links with a purpose."},"bookingRequired":{"type":"boolean","description":"true shows Booking required."},"bookingUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The page to book on."},"extraKinds":{"type":"array","items":{"enum":["hut","cable_car","activity","food","parking"]},"description":"Further roles of the same place."},"insideId":{"anyOf":[{"type":"string","x-sceniq-id":"facilities"},{"type":"null"}],"description":"The place this one sits inside."},"needsParentTicket":{"type":"boolean","description":"true when entering needs the parent place's ticket."},"conditions":{"anyOf":[{"$ref":"#/components/schemas/PlaceConditions"},{"type":"null"}],"description":"Conditions shown as chips."},"costUnit":{"anyOf":[{"enum":["per_person","per_night","per_person_night","per_room","per_vehicle","per_trip","per_hour","per_day"]},{"type":"null"}],"description":"What costRaw counts."},"parking":{"anyOf":[{"$ref":"#/components/schemas/ParkingInfo"},{"type":"null"}],"description":"Parking details."},"transport":{"anyOf":[{"$ref":"#/components/schemas/TransportInfo"},{"type":"null"}],"description":"Transport details."},"activity":{"anyOf":[{"$ref":"#/components/schemas/ActivityInfo"},{"type":"null"}],"description":"Tour and activity details."},"gatewayTown":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The town the place sits in when it is far from the spot on purpose."},"status":{"anyOf":[{"$ref":"#/components/schemas/StatusNotice"},{"type":"null"}],"description":"A closure notice."},"fees":{"type":"array","items":{"$ref":"#/components/schemas/Fee"},"description":"Fees and tickets."},"schedule":{"anyOf":[{"$ref":"#/components/schemas/Schedule"},{"type":"null"}],"description":"Structured opening hours."},"sources":{"type":"array","items":{"$ref":"#/components/schemas/SourceRef"},"description":"Research evidence, never shown to buyers."},"reviewNotes":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Notes for the creator's review, never shown to buyers."},"factsCheckedOn":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The day the facts were last checked (YYYY-MM-DD)."},"reviewBy":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The day the facts need a new check (YYYY-MM-DD)."},"createdAt":{"type":"number","description":"When the row was created (Unix time in milliseconds)."},"updatedAt":{"type":"number","description":"When the row last changed (Unix time in milliseconds)."},"warnings":{"type":"array","items":{"type":"string"},"description":"Notes about things the write accepted but you should look at (a plain http link). Present only when there are any."}},"required":["facilityId","kind","type","spotKeys","name","operator","description","costRaw","openRaw","website","mapsUrl","extraProps","lat","lon","osmId","googlePlaceId","country","timeZone","links","bookingRequired","bookingUrl","extraKinds","insideId","needsParentTicket","conditions","costUnit","parking","transport","activity","gatewayTown","status","fees","schedule","sources","reviewNotes","factsCheckedOn","reviewBy","createdAt","updatedAt"],"additionalProperties":false,"description":"A place after create_facility, with the write's warnings.","x-group":"Objects"},"Photo":{"type":"object","properties":{"mediaId":{"type":"string","x-sceniq-id":"media","description":"The photo's id."},"url":{"type":"string","description":"The stored photo (at most 2048 px on the long side)."},"thumbUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The ~640 px variant, or null until it is made."},"ownerType":{"enum":["spot","product","collection","listing"],"description":"What the photo belongs to."},"ownerId":{"type":"string","description":"The owner row's id."},"caption":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Caption."},"alt":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Alt text."},"credit":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Photographer credit."},"width":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Width in pixels."},"height":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Height in pixels."},"order":{"type":"number","description":"Position in the owner's gallery (ascending, fractional)."},"focalX":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Focal point from 0 (left) to 1 (right)."},"focalY":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Focal point from 0 (top) to 1 (bottom)."},"sourcePageUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The page the photo was licensed from."},"licence":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Licence name."},"creditUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The photographer's profile page."},"shows":{"anyOf":[{"$ref":"#/components/schemas/PhotoShows"},{"type":"null"}],"description":"What the photo shows."},"takenAt":{"anyOf":[{"$ref":"#/components/schemas/PhotoTakenAt"},{"type":"null"}],"description":"Where it was taken."},"locationVerifiedBy":{"anyOf":[{"enum":["geotag","landmark","photographer_caption","creator","other"]},{"type":"null"}],"description":"How the location was confirmed."},"capturedOn":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Capture date (YYYY-MM-DD)."},"reviewNotes":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Notes for the creator's review, never shown to buyers."}},"required":["mediaId","url","thumbUrl","ownerType","ownerId","caption","alt","credit","width","height","order","focalX","focalY","sourcePageUrl","licence","creditUrl","shows","takenAt","locationVerifiedBy","capturedOn","reviewNotes"],"additionalProperties":false,"description":"A photo with its metadata and owner.","x-group":"Objects"},"PublishGate":{"type":"object","properties":{"code":{"enum":["agreement_outdated","no_spots","missing_coordinates","missing_photos","no_price"],"description":"Which gate is open."},"message":{"type":"string","description":"What to fix, in plain words."}},"required":["code","message"],"additionalProperties":false,"description":"An open publish gate.","x-group":"Objects"},"StaleFact":{"type":"object","properties":{"kind":{"enum":["spot","place","route","area","photo"],"description":"The kind of row."},"id":{"type":"string","description":"The row's id."},"name":{"type":"string","description":"The row's name."},"field":{"type":"string","description":"The field that needs a new check (fees, status, schedule, reviewBy ...)."},"reason":{"enum":["review_due","ended","not_checked_recently"],"description":"Why it is listed."},"date":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The date that passed (YYYY-MM-DD)."},"detail":{"type":"string","description":"What ran out, in plain words."}},"required":["kind","id","name","field","reason","date","detail"],"additionalProperties":false,"description":"A dated fact that ran out or needs a new check.","x-group":"Objects"},"Readiness":{"type":"object","properties":{"productId":{"type":"string","x-sceniq-id":"products","description":"The guide's id."},"name":{"type":"string","description":"The guide's title."},"status":{"enum":["draft","published","archived"],"description":"draft, published or archived."},"canPublish":{"type":"boolean","description":"true when no publish gate is open."},"blocking":{"type":"array","items":{"$ref":"#/components/schemas/PublishGate"},"description":"The publish gates that are open: the same check publishing enforces."},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","description":"A stable code for the warning (see the readiness guide for the list)."},"message":{"type":"string","description":"What it means, in plain words."}},"required":["code","message"],"additionalProperties":false},"description":"Checks that do not block a publish but deserve a look."},"checks":{"type":"object","properties":{"staleFacts":{"type":"array","items":{"$ref":"#/components/schemas/StaleFact"},"description":"Dated facts past their dates."},"reviewNotes":{"type":"array","items":{"type":"object","properties":{"kind":{"enum":["spot","place","route","photo"],"description":"The kind of row."},"id":{"type":"string","description":"The row's id."},"name":{"type":"string","description":"The row's name."},"note":{"type":"string","description":"The review note."}},"required":["kind","id","name","note"],"additionalProperties":false},"description":"Every reviewNotes entry in the guide."},"spotsWithoutSources":{"type":"number","description":"Live spots without any source."},"links":{"type":"object","properties":{"total":{"type":"number","description":"Links buyers can open."},"flagged":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string","description":"The link."},"state":{"type":"string","description":"Its state (broken, suspicious, tls, redirected)."},"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Why, in words."},"finalUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Where a redirect ends."},"usedBy":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","description":"The kind of row."},"name":{"type":"string","description":"The row's name."},"field":{"type":"string","description":"The field that holds the link."}},"required":["kind","name","field"],"additionalProperties":false},"description":"Where the link is used."}},"required":["url","state","reason","finalUrl","usedBy"],"additionalProperties":false},"description":"Links that look dead, parked or redirected."},"unverifiable":{"type":"number","description":"Links on sites that turn scripts away."},"unchecked":{"type":"number","description":"Links not checked yet."}},"required":["total","flagged","unverifiable","unchecked"],"additionalProperties":false,"description":"Link health (get_link_report has every link)."},"photos":{"type":"object","properties":{"farFromPin":{"type":"array","items":{"type":"object","properties":{"kind":{"enum":["spot","place","route","area","photo"],"description":"Always photo."},"id":{"type":"string","description":"The photo's id."},"name":{"type":"string","description":"The photo's caption or file."},"spotId":{"type":"string","description":"The spot the photo belongs to."},"spotTitle":{"type":"string","description":"The spot's title."},"detail":{"type":"string","description":"What looks wrong."}},"required":["kind","id","name","spotId","spotTitle","detail"],"additionalProperties":false},"description":"Photos with a precise location more than 2 km from the pin."},"judgement":{"type":"array","items":{"type":"object","properties":{"kind":{"enum":["spot","place","route","area","photo"],"description":"Always photo."},"id":{"type":"string","description":"The photo's id."},"name":{"type":"string","description":"The photo's caption or file."},"spotId":{"type":"string","description":"The spot the photo belongs to."},"spotTitle":{"type":"string","description":"The spot's title."},"detail":{"type":"string","description":"What looks wrong."}},"required":["kind","id","name","spotId","spotTitle","detail"],"additionalProperties":false},"description":"Photos whose location needs the creator's judgement."},"beforeChange":{"type":"array","items":{"type":"object","properties":{"kind":{"enum":["spot","place","route","area","photo"],"description":"Always photo."},"id":{"type":"string","description":"The photo's id."},"name":{"type":"string","description":"The photo's caption or file."},"spotId":{"type":"string","description":"The spot the photo belongs to."},"spotTitle":{"type":"string","description":"The spot's title."},"detail":{"type":"string","description":"What looks wrong."}},"required":["kind","id","name","spotId","spotTitle","detail"],"additionalProperties":false},"description":"Photos captured before the spot's siteChange."},"nearDuplicates":{"type":"array","items":{"type":"object","properties":{"kind":{"enum":["spot","place","route","area","photo"],"description":"Always photo."},"id":{"type":"string","description":"The photo's id."},"name":{"type":"string","description":"The photo's caption or file."},"spotId":{"type":"string","description":"The spot the photo belongs to."},"spotTitle":{"type":"string","description":"The spot's title."},"detail":{"type":"string","description":"What looks wrong."}},"required":["kind","id","name","spotId","spotTitle","detail"],"additionalProperties":false},"description":"Photos that look like another photo of the guide."}},"required":["farFromPin","judgement","beforeChange","nearDuplicates"],"additionalProperties":false,"description":"Photo checks."},"places":{"type":"object","properties":{"farFromSpots":{"type":"array","items":{"type":"object","properties":{"kind":{"enum":["spot","place","route","area","photo"],"description":"The kind of row."},"id":{"type":"string","description":"The row's id."},"name":{"type":"string","description":"The row's name."},"detail":{"type":"string","description":"What looks wrong."}},"required":["kind","id","name","detail"],"additionalProperties":false},"description":"Places far from the spots they serve."},"zoneDiffers":{"type":"array","items":{"type":"object","properties":{"kind":{"enum":["spot","place","route","area","photo"],"description":"The kind of row."},"id":{"type":"string","description":"The row's id."},"name":{"type":"string","description":"The row's name."},"detail":{"type":"string","description":"What looks wrong."}},"required":["kind","id","name","detail"],"additionalProperties":false},"description":"Places in another time zone than their spot."},"distanceTooShort":{"type":"array","items":{"type":"object","properties":{"kind":{"enum":["spot","place","route","area","photo"],"description":"The kind of row."},"id":{"type":"string","description":"The row's id."},"name":{"type":"string","description":"The row's name."},"detail":{"type":"string","description":"What looks wrong."}},"required":["kind","id","name","detail"],"additionalProperties":false},"description":"Stated distances shorter than the straight line."},"searchLinks":{"type":"array","items":{"type":"object","properties":{"kind":{"enum":["spot","place","route","area","photo"],"description":"The kind of row."},"id":{"type":"string","description":"The row's id."},"name":{"type":"string","description":"The row's name."},"detail":{"type":"string","description":"What looks wrong."}},"required":["kind","id","name","detail"],"additionalProperties":false},"description":"Map links that are a text search (they can open a namesake)."}},"required":["farFromSpots","zoneDiffers","distanceTooShort","searchLinks"],"additionalProperties":false,"description":"Place checks."},"text":{"type":"object","properties":{"pastDates":{"type":"array","items":{"type":"object","properties":{"kind":{"enum":["spot","place","route","area","photo"],"description":"The kind of row."},"id":{"type":"string","description":"The row's id."},"name":{"type":"string","description":"The row's name."},"field":{"type":"string","description":"The field the text is in."},"detail":{"type":"string","description":"What looks wrong."}},"required":["kind","id","name","field","detail"],"additionalProperties":false},"description":"Dates in the text that have passed."},"monthMismatch":{"type":"array","items":{"type":"object","properties":{"kind":{"enum":["spot","place","route","area","photo"],"description":"The kind of row."},"id":{"type":"string","description":"The row's id."},"name":{"type":"string","description":"The row's name."},"field":{"type":"string","description":"The field the text is in."},"detail":{"type":"string","description":"What looks wrong."}},"required":["kind","id","name","field","detail"],"additionalProperties":false},"description":"Best months in the text missing from a month property."},"directions":{"type":"array","items":{"type":"object","properties":{"kind":{"enum":["spot","place","route","area","photo"],"description":"The kind of row."},"id":{"type":"string","description":"The row's id."},"name":{"type":"string","description":"The row's name."},"field":{"type":"string","description":"The field the text is in."},"detail":{"type":"string","description":"What looks wrong."}},"required":["kind","id","name","field","detail"],"additionalProperties":false},"description":"Directions that disagree with the pins."}},"required":["pastDates","monthMismatch","directions"],"additionalProperties":false,"description":"Text checks."},"light":{"type":"array","items":{"type":"object","properties":{"kind":{"enum":["spot","place","route","area","photo"],"description":"The kind of row."},"id":{"type":"string","description":"The row's id."},"name":{"type":"string","description":"The row's name."},"field":{"type":"string","description":"The field the text is in."},"detail":{"type":"string","description":"What looks wrong."}},"required":["kind","id","name","field","detail"],"additionalProperties":false},"description":"Best light outside the opening hours."},"pins":{"type":"array","items":{"type":"object","properties":{"kind":{"enum":["spot","place","route","area","photo"],"description":"The kind of row."},"id":{"type":"string","description":"The row's id."},"name":{"type":"string","description":"The row's name."},"field":{"type":"string","description":"The field the text is in."},"detail":{"type":"string","description":"What looks wrong."}},"required":["kind","id","name","field","detail"],"additionalProperties":false},"description":"Extra pins far from their spot."},"agreementCurrent":{"type":"boolean","description":"Whether the creator accepted the current agreement."},"spotCount":{"type":"number","description":"Live spots."},"archivedSpotCount":{"type":"number","description":"Archived spots."},"missingCoordinates":{"type":"array","items":{"type":"object","properties":{"spotId":{"type":"string","x-sceniq-id":"spots","description":"The spot's id."},"title":{"type":"string","description":"The spot's title."}},"required":["spotId","title"],"additionalProperties":false},"description":"Live spots without a pin."},"coordinateOutliers":{"type":"array","items":{"type":"object","properties":{"spotId":{"type":"string","x-sceniq-id":"spots","description":"The spot's id."},"title":{"type":"string","description":"The spot's title."},"distanceKm":{"type":"number","description":"Distance from the guide's center in kilometers."}},"required":["spotId","title","distanceKm"],"additionalProperties":false},"description":"Spots unusually far from the others."},"outlierThresholdKm":{"type":"number","description":"The distance above which a spot counts as an outlier."},"outsideRegion":{"type":"array","items":{"type":"object","properties":{"spotId":{"type":"string","x-sceniq-id":"spots","description":"The spot's id."},"title":{"type":"string","description":"The spot's title."}},"required":["spotId","title"],"additionalProperties":false},"description":"Spots outside the region's bbox."},"spotsWithoutPhotos":{"type":"array","items":{"type":"object","properties":{"spotId":{"type":"string","x-sceniq-id":"spots","description":"The spot's id."},"title":{"type":"string","description":"The spot's title."}},"required":["spotId","title"],"additionalProperties":false},"description":"Live spots with photos on but none uploaded."},"spotsWithoutText":{"type":"array","items":{"type":"object","properties":{"spotId":{"type":"string","x-sceniq-id":"spots","description":"The spot's id."},"title":{"type":"string","description":"The spot's title."}},"required":["spotId","title"],"additionalProperties":false},"description":"Spots without a short or a long description."},"photoCount":{"type":"number","description":"Photos in the guide."},"photosWithoutCredit":{"type":"number","description":"Photos without a credit."},"price":{"anyOf":[{"type":"object","properties":{"amountMinor":{"type":"number","description":"The price in minor units (2900 is 29.00)."},"currency":{"type":"string","description":"ISO 4217 code in lower case (usd, eur, chf)."}},"required":["amountMinor","currency"],"additionalProperties":false},{"type":"null"}],"description":"The active price."},"chapterCount":{"type":"number","description":"Chapters and collections."},"routeCount":{"type":"number","description":"Routes."},"region":{"anyOf":[{"$ref":"#/components/schemas/MapRegion"},{"type":"null"}],"description":"The map region."},"storeTags":{"type":"array","items":{"type":"string"},"description":"Store tags."},"country":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Country code, or null for worldwide."},"hasThumbnail":{"type":"boolean","description":"Whether a store thumbnail is set."},"salesPage":{"type":"object","properties":{"draftProblems":{"type":"array","items":{"type":"string"},"description":"What the sales page draft still lacks."},"exists":{"type":"boolean","description":"Whether a sales page draft exists."},"published":{"type":"boolean","description":"Whether the sales page is published."}},"required":["draftProblems","exists","published"],"additionalProperties":false,"description":"The sales page."},"lastApiWriteAt":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"When a key last changed the guide."}},"required":["staleFacts","reviewNotes","spotsWithoutSources","links","photos","places","text","light","pins","agreementCurrent","spotCount","archivedSpotCount","missingCoordinates","coordinateOutliers","outlierThresholdKm","outsideRegion","spotsWithoutPhotos","spotsWithoutText","photoCount","photosWithoutCredit","price","chapterCount","routeCount","region","storeTags","country","hasThumbnail","salesPage","lastApiWriteAt"],"additionalProperties":false,"description":"The rows behind each warning and gate."},"handoff":{"type":"object","properties":{"remaining":{"type":"array","items":{"type":"string"},"description":"The clicks only the creator can make, still open."},"studioUrl":{"type":"string","description":"Where the creator publishes the guide."},"salesPageUrl":{"type":"string","description":"Where the creator publishes the sales page."}},"required":["remaining","studioUrl","salesPageUrl"],"additionalProperties":false,"description":"What the creator does in the studio."},"reviewUrl":{"type":"string","description":"The guide in the studio, for the creator's review."},"nextStep":{"type":"string","description":"One sentence on what to do next."}},"required":["productId","name","status","canPublish","blocking","warnings","checks","handoff","reviewUrl","nextStep"],"additionalProperties":false,"description":"The publish checklist of a guide.","x-group":"Objects"},"StaleNotices":{"type":"object","properties":{"productId":{"type":"string","x-sceniq-id":"products","description":"The guide's id."},"today":{"type":"string","description":"The date the check ran for (YYYY-MM-DD)."},"count":{"type":"number","description":"Number of notices."},"notices":{"type":"array","items":{"$ref":"#/components/schemas/StaleFact"},"description":"Dated facts that ran out or need a new check."}},"required":["productId","today","count","notices"],"additionalProperties":false,"description":"The stale facts of a guide.","x-group":"Objects"},"PublishStatus":{"type":"object","properties":{"productId":{"type":"string","x-sceniq-id":"products","description":"The guide's id."},"name":{"type":"string","description":"The guide's title."},"status":{"enum":["draft","published","archived"],"description":"draft, published or archived."},"live":{"type":"boolean","description":"true when the guide is on sale."},"published":{"anyOf":[{"type":"object","properties":{"publishedAt":{"type":"number","description":"When the live version went live (Unix time in milliseconds)."},"version":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"The live version's number."}},"required":["publishedAt","version"],"additionalProperties":false},{"type":"null"}],"description":"What buyers see, or null before the first build."},"hasUnpublishedChanges":{"type":"boolean","description":"true when the draft holds changes buyers do not see yet."},"lastEditAt":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"When the draft last changed."},"pendingSince":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"When a publish started building; null when none is running."},"blocking":{"type":"array","items":{"$ref":"#/components/schemas/PublishGate"},"description":"The publish gates that are open."},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","description":"A stable code for the warning (see the readiness guide for the list)."},"message":{"type":"string","description":"What it means, in plain words."}},"required":["code","message"],"additionalProperties":false},"description":"Problems that do not block: review_due, stale_facts, link_problems."},"canPublishChanges":{"type":"boolean","description":"true when publish_changes would queue a build now."},"nextStep":{"type":"string","description":"One sentence on what to do next."},"reviewUrl":{"type":"string","description":"The guide in the studio."}},"required":["productId","name","status","live","published","hasUnpublishedChanges","lastEditAt","pendingSince","blocking","warnings","canPublishChanges","nextStep","reviewUrl"],"additionalProperties":false,"description":"What buyers see and what a publish would do.","x-group":"Objects"},"PublishQueued":{"type":"object","properties":{"queued":{"type":"boolean","description":"true when this call queued a build; false when one was already running."},"productId":{"type":"string","x-sceniq-id":"products","description":"The guide's id."},"name":{"type":"string","description":"The guide's title."},"status":{"enum":["draft","published","archived"],"description":"draft, published or archived."},"live":{"type":"boolean","description":"true when the guide is on sale."},"published":{"anyOf":[{"type":"object","properties":{"publishedAt":{"type":"number","description":"When the live version went live (Unix time in milliseconds)."},"version":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"The live version's number."}},"required":["publishedAt","version"],"additionalProperties":false},{"type":"null"}],"description":"What buyers see, or null before the first build."},"hasUnpublishedChanges":{"type":"boolean","description":"true when the draft holds changes buyers do not see yet."},"lastEditAt":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"When the draft last changed."},"pendingSince":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"When a publish started building; null when none is running."},"blocking":{"type":"array","items":{"$ref":"#/components/schemas/PublishGate"},"description":"The publish gates that are open."},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","description":"A stable code for the warning (see the readiness guide for the list)."},"message":{"type":"string","description":"What it means, in plain words."}},"required":["code","message"],"additionalProperties":false},"description":"Problems that do not block: review_due, stale_facts, link_problems."},"canPublishChanges":{"type":"boolean","description":"true when publish_changes would queue a build now."},"nextStep":{"type":"string","description":"One sentence on what to do next."},"reviewUrl":{"type":"string","description":"The guide in the studio."}},"required":["queued","productId","name","status","live","published","hasUnpublishedChanges","lastEditAt","pendingSince","blocking","warnings","canPublishChanges","nextStep","reviewUrl"],"additionalProperties":false,"description":"The publish status after publish_changes.","x-group":"Objects"},"LinkReportEntry":{"type":"object","properties":{"url":{"type":"string","description":"The link exactly as stored."},"state":{"enum":["unchecked","ok","redirected","unverifiable","broken","suspicious","tls"],"description":"The last check's verdict."},"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Why, in words."},"httpStatus":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"The HTTP status of the last check."},"finalUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Where a redirect ends."},"checkedAt":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"When it was last checked."},"lastOkAt":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"When it last worked."},"manualOkOn":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The day it was confirmed by hand (YYYY-MM-DD)."},"manualNote":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"How it was confirmed."},"flagged":{"type":"boolean","description":"true when broken, suspicious, tls or redirected and not confirmed by hand."},"usedBy":{"type":"array","items":{"type":"object","properties":{"kind":{"enum":["spot","place","route","area","photo"],"description":"The kind of row."},"id":{"type":"string","description":"The row's id."},"name":{"type":"string","description":"The row's name."},"field":{"type":"string","description":"The field that holds the link."}},"required":["kind","id","name","field"],"additionalProperties":false},"description":"Where the link is used."}},"required":["url","state","reason","httpStatus","finalUrl","checkedAt","lastOkAt","manualOkOn","manualNote","flagged","usedBy"],"additionalProperties":false,"description":"One link with its last check.","x-group":"Objects"},"LinkReport":{"type":"object","properties":{"productId":{"type":"string","x-sceniq-id":"products","description":"The guide's id."},"total":{"type":"number","description":"Links buyers can open."},"counts":{"type":"object","additionalProperties":{"type":"number"},"description":"How many links are in each state."},"flagged":{"type":"number","description":"Links flagged for a look."},"links":{"type":"array","items":{"$ref":"#/components/schemas/LinkReportEntry"},"description":"Every link with its last check."}},"required":["productId","total","counts","flagged","links"],"additionalProperties":false,"description":"Every link buyers can open, with its health.","x-group":"Objects"},"Profile":{"type":"object","properties":{"creatorId":{"type":"string","x-sceniq-id":"creators","description":"The creator's id."},"slug":{"type":"string","description":"The creator's URL slug (read-only)."},"displayName":{"type":"string","description":"The public brand name."},"realName":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The legal name on the studio profile."},"bio":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The bio."},"email":{"type":"string","description":"The login email (read-only)."},"avatarUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The avatar."},"socials":{"type":"array","items":{"$ref":"#/components/schemas/SocialLink"},"description":"Social links."},"role":{"enum":["owner","editor"],"description":"The key owner's role on the creator account."}},"required":["creatorId","slug","displayName","realName","bio","email","avatarUrl","socials","role"],"additionalProperties":false,"description":"The creator's public profile.","x-group":"Objects"},"SalesPage":{"type":"object","properties":{"productId":{"type":"string","x-sceniq-id":"products","description":"The guide's id."},"listing":{"anyOf":[{"type":"object","properties":{"listingId":{"type":"string","x-sceniq-id":"listings","description":"The sales page's id."},"status":{"enum":["published","unpublished"],"description":"Whether a version is live."},"baseLanguage":{"type":"string","description":"The language of draftConfig."},"draftConfig":{"$ref":"#/components/schemas/ListingConfig","description":"The draft: what save_sales_page_draft replaces."},"draftUpdatedAt":{"type":"number","description":"When the draft last changed."},"publishedConfig":{"anyOf":[{"$ref":"#/components/schemas/ListingConfig"},{"type":"null"}],"description":"What buyers see."},"publishedAt":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"When it was last published."},"publishedConfigVersion":{"type":"number","description":"The live version's number."},"locales":{"type":"array","items":{"type":"string"},"description":"Published translations as language codes, besides baseLanguage ([] for a page in one language)."},"metaTitle":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The search result title."},"metaDescription":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The search result description."},"updatedAt":{"type":"number","description":"When the row last changed (Unix time in milliseconds)."}},"required":["listingId","status","baseLanguage","draftConfig","draftUpdatedAt","publishedConfig","publishedAt","publishedConfigVersion","locales","metaTitle","metaDescription","updatedAt"],"additionalProperties":false},{"type":"null"}],"description":"The default sales page, or null before a draft exists."},"mediaMap":{"type":"object","additionalProperties":{"type":"object","properties":{"id":{"type":"string","x-sceniq-id":"media","description":"The photo's id."},"url":{"type":"string","description":"The photo's URL."},"caption":{"type":"string","description":"Caption."},"credit":{"type":"string","description":"Photographer credit."},"width":{"type":"number","description":"Width in pixels."},"height":{"type":"number","description":"Height in pixels."},"order":{"type":"number","description":"Position."}},"required":["id","url","order"],"additionalProperties":false},"description":"The photos the sales page may use, keyed by mediaId."},"publishing":{"type":"string","description":"Who publishes the sales page (the creator, in the studio)."}},"required":["productId","listing","mediaMap","publishing"],"additionalProperties":false,"description":"The default sales page and the photos it may use.","x-group":"Objects"},"Whoami":{"type":"object","properties":{"creator":{"type":"object","properties":{"creatorId":{"type":"string","x-sceniq-id":"creators","description":"The creator's id."},"slug":{"type":"string","description":"The creator's URL slug."},"displayName":{"type":"string","description":"The public brand name."},"role":{"enum":["owner","editor"],"description":"The key owner's role on the account."}},"required":["creatorId","slug","displayName","role"],"additionalProperties":false,"description":"The creator this key is bound to."},"key":{"type":"object","properties":{"name":{"type":"string","description":"The key's name."},"scopes":{"type":"array","items":{"enum":["read","write","publish"]},"description":"What the key may do."}},"required":["name","scopes"],"additionalProperties":false,"description":"The key."},"limits":{"type":"object","properties":{"requestsPerMinutePerKey":{"type":"number","description":"Requests per minute for this key."},"requestsPerHourPerCreator":{"type":"number","description":"Requests per hour across the creator's keys."},"uploadsPerMinutePerKey":{"type":"number","description":"Photo uploads per minute for this key (a batch counts each file)."},"maxUploadBytes":{"type":"number","description":"The largest photo accepted, in bytes."}},"required":["requestsPerMinutePerKey","requestsPerHourPerCreator","uploadsPerMinutePerKey","maxUploadBytes"],"additionalProperties":false,"description":"Request limits."},"endpoints":{"type":"object","properties":{"rest":{"type":"string","description":"REST base URL."},"mcp":{"type":"string","description":"MCP endpoint."},"upload":{"type":"string","description":"Photo upload."},"uploadBatch":{"type":"string","description":"Batch photo upload."},"openapi":{"type":"string","description":"OpenAPI document."},"skill":{"type":"string","description":"The authoring guide as a SKILL.md."},"docs":{"type":"string","description":"The developer page, with the way into these docs."}},"required":["rest","mcp","upload","uploadBatch","openapi","skill","docs"],"additionalProperties":false,"description":"The URLs to call, on the Sceniq domain."},"directEndpoints":{"anyOf":[{"type":"object","properties":{"rest":{"type":"string","description":"REST base URL."},"mcp":{"type":"string","description":"MCP endpoint."},"upload":{"type":"string","description":"Photo upload."},"uploadBatch":{"type":"string","description":"Batch photo upload."},"openapi":{"type":"string","description":"OpenAPI document."}},"required":["rest","mcp","upload","uploadBatch","openapi"],"additionalProperties":false},{"type":"null"}],"description":"The backend origin the Sceniq URLs proxy to, for harnesses without the proxy."},"dashboard":{"type":"object","properties":{"settingsUrl":{"type":"string","description":"Studio settings, where keys are made."}},"required":["settingsUrl"],"additionalProperties":false,"description":"Studio links."},"authoringGuideVersion":{"type":"string","description":"The authoring guide's version; reload it when it changes."},"publishing":{"type":"string","description":"What this key may publish, in plain words."}},"required":["creator","key","limits","endpoints","directEndpoints","dashboard","authoringGuideVersion","publishing"],"additionalProperties":false,"description":"The key, its creator, the limits and the endpoints.","x-group":"Objects"},"UploadedPhoto":{"type":"object","properties":{"mediaId":{"type":"string","x-sceniq-id":"media","description":"The new photo's id."},"url":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The stored photo."},"thumbUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The 640 px thumbnail."},"ownerType":{"enum":["spot","product","collection","listing"],"description":"What the photo belongs to."},"ownerId":{"type":"string","description":"The owner row's id."},"caption":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Caption."},"credit":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Photographer credit."},"order":{"type":"number","description":"Position in the owner's gallery."},"contentType":{"type":"string","description":"The stored file's type (image/webp after optimizing)."},"width":{"type":"number","description":"Stored width in pixels."},"height":{"type":"number","description":"Stored height in pixels."},"bytes":{"type":"number","description":"Stored size in bytes."},"originalBytes":{"type":"number","description":"The uploaded file's size in bytes."},"optimized":{"type":"boolean","description":"false when the optimizer was unavailable and the metadata-stripped original was kept."},"metadataStripped":{"type":"boolean","description":"true when the upload carried EXIF, GPS, XMP or IPTC metadata (all removed)."},"thumbBytes":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"The thumbnail's size in bytes."},"capturedOn":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Capture date (YYYY-MM-DD), sent or read from the file."},"warnings":{"type":"array","items":{"type":"string"},"description":"Notes about things the write accepted but you should look at (a plain http link). Present only when there are any."}},"required":["mediaId","url","thumbUrl","ownerType","ownerId","caption","credit","order","contentType","width","height","bytes","originalBytes","optimized","metadataStripped","thumbBytes","capturedOn"],"additionalProperties":false,"description":"A photo after upload_media.","x-group":"Objects"},"UploadedBlob":{"type":"object","properties":{"storageId":{"type":"string","x-sceniq-id":"_storage","description":"The stored file's id: coverStorageId or photoStorageId."},"contentType":{"type":"string","description":"The stored file's type (image/webp after optimizing)."},"width":{"type":"number","description":"Stored width in pixels."},"height":{"type":"number","description":"Stored height in pixels."},"bytes":{"type":"number","description":"Stored size in bytes."},"originalBytes":{"type":"number","description":"The uploaded file's size in bytes."},"optimized":{"type":"boolean","description":"false when the optimizer was unavailable and the metadata-stripped original was kept."},"metadataStripped":{"type":"boolean","description":"true when the upload carried EXIF, GPS, XMP or IPTC metadata (all removed)."},"use":{"type":"string","description":"Where the storageId goes."}},"required":["storageId","contentType","width","height","bytes","originalBytes","optimized","metadataStripped","use"],"additionalProperties":false,"description":"A stored file after an upload with target=blob.","x-group":"Objects"},"BatchUpload":{"type":"object","properties":{"uploaded":{"type":"number","description":"Files stored."},"failed":{"type":"number","description":"Files refused."},"results":{"type":"array","items":{"type":"object","properties":{"file":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The form field name from the manifest."},"ok":{"type":"boolean","description":"Whether this file was stored."},"mediaId":{"type":"string","x-sceniq-id":"media","description":"The new photo's id (media uploads)."},"storageId":{"type":"string","x-sceniq-id":"_storage","description":"The stored file's id (target blob)."},"url":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The stored photo."},"thumbUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The thumbnail."},"ownerType":{"enum":["spot","product","collection","listing"],"description":"What the photo belongs to."},"ownerId":{"type":"string","description":"The owner row's id."},"caption":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Caption."},"credit":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Photographer credit."},"order":{"type":"number","description":"Position in the owner's gallery."},"contentType":{"type":"string","description":"The stored file's type."},"width":{"type":"number","description":"Stored width in pixels."},"height":{"type":"number","description":"Stored height in pixels."},"bytes":{"type":"number","description":"Stored size in bytes."},"thumbBytes":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"The thumbnail's size in bytes."},"originalBytes":{"type":"number","description":"The uploaded file's size in bytes."},"optimized":{"type":"boolean","description":"false when the original was kept."},"metadataStripped":{"type":"boolean","description":"true when metadata was removed."},"capturedOn":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Capture date."},"use":{"type":"string","description":"Where a storageId goes."},"warnings":{"type":"array","items":{"type":"string"},"description":"Notes about things the write accepted but you should look at (a plain http link). Present only when there are any."},"error":{"type":"object","properties":{"code":{"type":"string","description":"The error code (see Errors)."},"message":{"type":"string","description":"What went wrong."}},"required":["code","message"],"additionalProperties":false,"description":"Why the file was refused."}},"required":["file","ok"],"additionalProperties":false},"description":"One result per manifest item, in order."}},"required":["uploaded","failed","results"],"additionalProperties":false,"description":"The results of upload_media_batch.","x-group":"Objects"}}},"paths":{"/me":{"get":{"operationId":"whoami","summary":"Who this key belongs to, plus endpoints and limits","description":"Call first. Returns the creator this key is bound to, the key's scopes, the request limits, and the exact URLs for the REST API, the MCP endpoint and photo uploads.","tags":["account"],"x-scope":"read","x-stability":"stable","x-since":"2026-09-17","x-mcp-tool":"whoami","parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Whoami"},"examples":{"a_key_with_read_and_write":{"summary":"A key with read and write","value":{"creator":{"creatorId":"k97c2m4vx8r1q0d6s5t3n9p2w7y4h8b1","slug":"mara-lindgren","displayName":"Mara Lindgren","role":"owner"},"key":{"name":"Claude Code on the laptop","scopes":["read","write"]},"limits":{"requestsPerMinutePerKey":300,"requestsPerHourPerCreator":5000,"uploadsPerMinutePerKey":60,"maxUploadBytes":6291456},"endpoints":{"rest":"https://sceniq.earth/api/v1","mcp":"https://sceniq.earth/api/mcp","upload":"https://sceniq.earth/api/v1/media/upload","uploadBatch":"https://sceniq.earth/api/v1/media/upload-batch","openapi":"https://sceniq.earth/api/v1/openapi.json","skill":"https://sceniq.earth/developers/skill.md","docs":"https://sceniq.earth/developers"},"directEndpoints":{"rest":"https://quiet-heron-512.convex.site/v1","mcp":"https://quiet-heron-512.convex.site/mcp","upload":"https://quiet-heron-512.convex.site/v1/media/upload","uploadBatch":"https://quiet-heron-512.convex.site/v1/media/upload-batch","openapi":"https://quiet-heron-512.convex.site/v1/openapi.json"},"dashboard":{"settingsUrl":"https://creators.sceniq.earth/settings"},"authoringGuideVersion":"2026-09-30.3","publishing":"This key cannot publish. A new guide always ends with two clicks only the creator makes in the studio: Publish guide and Publish sales page; get_guide_readiness handoff lists what is left with its links. Hand the creator the reviewUrl, or ask them to mint a key with the publish option for publish_changes on a live guide."}},"a_key_with_the_publish_option":{"summary":"A key with the publish option","value":{"creator":{"creatorId":"k97c2m4vx8r1q0d6s5t3n9p2w7y4h8b1","slug":"mara-lindgren","displayName":"Mara Lindgren","role":"owner"},"key":{"name":"Claude Desktop, can publish","scopes":["read","write","publish"]},"limits":{"requestsPerMinutePerKey":300,"requestsPerHourPerCreator":5000,"uploadsPerMinutePerKey":60,"maxUploadBytes":6291456},"endpoints":{"rest":"https://sceniq.earth/api/v1","mcp":"https://sceniq.earth/api/mcp","upload":"https://sceniq.earth/api/v1/media/upload","uploadBatch":"https://sceniq.earth/api/v1/media/upload-batch","openapi":"https://sceniq.earth/api/v1/openapi.json","skill":"https://sceniq.earth/developers/skill.md","docs":"https://sceniq.earth/developers"},"directEndpoints":{"rest":"https://quiet-heron-512.convex.site/v1","mcp":"https://quiet-heron-512.convex.site/mcp","upload":"https://quiet-heron-512.convex.site/v1/media/upload","uploadBatch":"https://quiet-heron-512.convex.site/v1/media/upload-batch","openapi":"https://quiet-heron-512.convex.site/v1/openapi.json"},"dashboard":{"settingsUrl":"https://creators.sceniq.earth/settings"},"authoringGuideVersion":"2026-09-30.3","publishing":"This key can publish a live guide's changes: only when the creator asks, after get_publish_status shows no blocking items (publish_changes, then poll get_publish_status). A new guide always ends with two clicks only the creator makes in the studio: Publish guide (putting the draft on sale) and Publish sales page; get_guide_readiness handoff lists what is left with its links. Store visibility and the creator agreement stay in the dashboard too."}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}}},"/authoring-guide":{"get":{"operationId":"get_authoring_guide","summary":"The full Sceniq authoring playbook (markdown)","description":"Read before building anything. The rules an agent must follow on Sceniq: assistant not author, no invented facts or coordinates, creator-supplied photos with credits, the recommended workflow, field semantics and copy rules.","tags":["account"],"x-scope":"read","x-stability":"stable","x-since":"2026-09-17","x-mcp-tool":"get_authoring_guide","parameters":[],"responses":{"200":{"description":"OK","content":{"text/markdown":{"schema":{"type":"string"}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}}},"/guides":{"get":{"operationId":"list_guides","summary":"All guides of this creator (drafts included)","description":"Every guide with its status, store state, price, buyer count and studio link. Start here when the creator refers to an existing guide; get_guide has the spot count and the rest.","tags":["guides"],"x-scope":"read","x-stability":"stable","x-since":"2026-09-17","x-mcp-tool":"list_guides","parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"guides":{"type":"array","items":{"$ref":"#/components/schemas/GuideSummary"},"description":"Every guide of the creator, drafts included."}},"required":["guides"],"additionalProperties":false},"examples":{"list_every_guide_of_the_creator_drafts_included":{"summary":"List every guide of the creator, drafts included","value":{"guides":[{"productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","name":"American West: Parks at First Light","slug":"american-west-first-light","headline":"Twelve viewpoints across Yellowstone and Yosemite, timed for the light and the crowds.","status":"draft","visibleOnStore":false,"storeReviewStatus":null,"storeTags":["photography","hiking","road-trips"],"country":"US","price":{"amountMinor":2900,"currency":"usd"},"buyers":0,"createdAt":1789895640000,"updatedAt":1790586840000,"publishedAt":null,"dashboardUrl":"https://creators.sceniq.earth/products/j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","salesPageUrl":"https://sceniq.earth/mara-lindgren/american-west-first-light"},{"productId":"j57dq4n8r2v6x0b4f8k2p6t0w4y8c2g6","name":"Antarctic Peninsula by Expedition Ship","slug":"antarctic-peninsula-by-ship","headline":"The channels, bays and landings an expedition ship from Ushuaia can reach, and what the ice decides.","status":"published","visibleOnStore":true,"storeReviewStatus":"approved","storeTags":["photography","islands"],"country":"AQ","price":{"amountMinor":3900,"currency":"usd"},"buyers":38,"createdAt":1784017800000,"updatedAt":1790586840000,"publishedAt":1790241240000,"dashboardUrl":"https://creators.sceniq.earth/products/j57dq4n8r2v6x0b4f8k2p6t0w4y8c2g6","salesPageUrl":"https://sceniq.earth/mara-lindgren/antarctic-peninsula-by-ship"}]}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}},"post":{"operationId":"create_guide","summary":"Create a new draft guide","description":"Creates an empty draft map guide (status draft, not visible anywhere). Only do this when the creator asked for a new guide; otherwise edit the existing one. The slug derives from the name unless given.","tags":["guides"],"x-scope":"write","x-stability":"stable","x-since":"2026-09-17","x-mcp-tool":"create_guide","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Guide title, 1-120 characters, e.g. American West: Parks at First Light."},"slug":{"type":"string","description":"Optional URL slug (lowercase letters, digits, hyphens). Derived from the name when omitted."}},"required":["name"],"additionalProperties":false},"examples":{"create_a_draft_guide_with_your_own_slug":{"summary":"Create a draft guide with your own slug","value":{"name":"American West: Parks at First Light","slug":"american-west-first-light"}},"let_the_slug_derive_from_the_name":{"summary":"Let the slug derive from the name","value":{"name":"Patagonia: Torres del Paine and Fitz Roy"}}}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Guide"},"examples":{"create_a_draft_guide_with_your_own_slug":{"summary":"Create a draft guide with your own slug","value":{"productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","name":"American West: Parks at First Light","slug":"american-west-first-light","headline":null,"purchaseButtonText":null,"status":"draft","visibleOnStore":false,"storeReviewStatus":null,"storeReviewNote":null,"storeTags":[],"country":null,"reviewsShown":true,"buyerCountShown":false,"pricing":{"oneTimeEnabled":true,"subscriptionIncluded":false,"currency":"usd"},"originalLanguage":"en","createdAt":1789895640000,"updatedAt":1789895640000,"publishedAt":null,"lastApiWriteAt":null,"region":null,"areas":[],"mapStyle":null,"propertySchemaVersion":1,"properties":[],"price":null,"spotCount":0,"thumbnailUrl":null,"dashboardUrl":"https://creators.sceniq.earth/products/j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","salesPageUrl":"https://sceniq.earth/mara-lindgren/american-west-first-light"}},"let_the_slug_derive_from_the_name":{"summary":"Let the slug derive from the name","value":{"productId":"j57mtnsxbtctmt4347jg8s8nrgbqhybg","name":"Patagonia: Torres del Paine and Fitz Roy","slug":"patagonia-torres-del-paine-and-fitz-roy","headline":null,"purchaseButtonText":null,"status":"draft","visibleOnStore":false,"storeReviewStatus":null,"storeReviewNote":null,"storeTags":[],"country":null,"reviewsShown":true,"buyerCountShown":false,"pricing":{"oneTimeEnabled":true,"subscriptionIncluded":false,"currency":"usd"},"originalLanguage":"en","createdAt":1790673240000,"updatedAt":1790673240000,"publishedAt":null,"lastApiWriteAt":null,"region":null,"areas":[],"mapStyle":null,"propertySchemaVersion":1,"properties":[],"price":null,"spotCount":0,"thumbnailUrl":null,"dashboardUrl":"https://creators.sceniq.earth/products/j57mtnsxbtctmt4347jg8s8nrgbqhybg","salesPageUrl":"https://sceniq.earth/mara-lindgren/patagonia-torres-del-paine-and-fitz-roy"}}}}}},"400":{"description":"Invalid request: invalid_argument, invalid_request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}},"invalid_request":{"summary":"The input was refused","value":{"error":{"code":"invalid_request","message":"A writer refused a value: a map link on a host that is not allowed, a title that is too long, a date that does not exist, too many items in a list. The message is the writer's own sentence."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: api_scope_required, forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"api_scope_required":{"summary":"The key lacks a scope","value":{"error":{"code":"api_scope_required","message":"A read-only key called a write operation, or a key without the publish option called publish_changes."}}},"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"413":{"description":"Too large: payload_too_large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"payload_too_large":{"summary":"The request is too large","value":{"error":{"code":"payload_too_large","message":"A JSON body over 2 MB, an image over 6 MB, a batch upload over 19 MB, or an MCP message over 2 MB."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}}},"/guides/{productId}":{"get":{"operationId":"get_guide","summary":"One guide: settings, region, properties, price, counts","description":"The guide shell: product fields, map region, areas (parks, islands, regions spots can point at), custom property definitions (keys and option ids you need for spot customValues), active price, spot and photo counts.","tags":["guides"],"x-scope":"read","x-stability":"stable","x-since":"2026-09-17","x-mcp-tool":"get_guide","parameters":[{"name":"productId","in":"path","required":true,"description":"Id of the guide (a product of type map). From list_guides or create_guide.","schema":{"type":"string","x-sceniq-id":"products"},"example":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuideDetail"},"examples":{"read_a_guide_s_settings_areas_properties_and_counts":{"summary":"Read a guide's settings, areas, properties and counts","value":{"productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","name":"American West: Parks at First Light","slug":"american-west-first-light","headline":"Twelve viewpoints across Yellowstone and Yosemite, timed for the light and the crowds.","purchaseButtonText":null,"status":"draft","visibleOnStore":false,"storeReviewStatus":null,"storeReviewNote":null,"storeTags":["photography","hiking","road-trips"],"country":"US","reviewsShown":true,"buyerCountShown":false,"pricing":{"oneTimeEnabled":true,"subscriptionIncluded":false,"currency":"usd"},"originalLanguage":"en","createdAt":1789895640000,"updatedAt":1790586840000,"publishedAt":null,"lastApiWriteAt":1790586840000,"region":{"label":"Yellowstone and Yosemite","centerLat":41.2,"centerLon":-115,"defaultZoom":5,"bbox":[-120,37.4,-109.8,45.2]},"areas":[{"id":"area_01m3gvdap06m6mx2kp4t553d6g","name":"Yellowstone National Park","kind":"park","note":"One entrance pass covers every spot in the Yellowstone chapter. Cell coverage is patchy between the geyser basins; download the guide before you drive in.","season":"Most park roads are open to cars from May to early November.","rules":[{"text":"Stay on boardwalks and marked trails in every thermal area.","kind":"other","sourceUrl":"https://www.nps.gov/yell/planyourvisit/safety.htm"}],"fees":[{"label":"Park entrance, private vehicle, 7 days","amount":35,"currency":"USD","per":"vehicle","paidWhere":"online","sourceUrl":"https://www.nps.gov/yell/planyourvisit/fees.htm","checkedOn":"2026-09-20"}],"links":[{"kind":"official","url":"https://www.nps.gov/yell/index.htm","label":"Yellowstone National Park (NPS)"},{"kind":"status","url":"https://www.nps.gov/yell/planyourvisit/conditions.htm","label":"Park road status"}],"sources":[{"url":"https://www.nps.gov/yell/planyourvisit/fees.htm","kind":"page","capturedOn":"2026-09-20","supports":["fees"]}]},{"id":"area_01m3gvgcb04pf38p66vz544w1b","name":"Yosemite National Park","kind":"park","season":"Open all year. Glacier Point Road and Tioga Road close to cars in winter.","rules":[{"text":"Glacier Point Road and Tioga Road are closed to cars in winter, usually from November to late May.","kind":"vehicle","months":[11,12,1,2,3,4,5],"appliesTo":"car","sourceUrl":"https://www.nps.gov/yose/planyourvisit/conditions.htm"}],"fees":[{"label":"Park entrance, private vehicle, 7 days","amount":35,"currency":"USD","per":"vehicle","sourceUrl":"https://www.nps.gov/yose/planyourvisit/fees.htm","checkedOn":"2026-09-20"}],"links":[{"kind":"official","url":"https://www.nps.gov/yose/index.htm","label":"Yosemite National Park (NPS)"},{"kind":"timetable","url":"https://yarts.com/","label":"YARTS buses into the valley"}]}],"mapStyle":null,"propertySchemaVersion":6,"properties":[{"propertyDefId":"kh75t2w9q4r6y8v0j1p3p5a7s9d1f3g5","key":"best_time","label":"Best time","kind":"singleSelect","order":0,"required":false,"filterable":true,"placeholder":null,"numUnit":null,"options":[{"id":"sunrise","label":"Sunrise","order":0,"archived":false},{"id":"morning","label":"Morning","order":1,"archived":false},{"id":"midday","label":"Midday","order":2,"archived":false},{"id":"sunset","label":"Sunset","order":3,"archived":false}],"archived":false,"schemaVersion":2},{"propertyDefId":"kh7b3n5m7q9w1e3r5t7y9v1j3p5p7a9s","key":"crowds","label":"Crowds","kind":"singleSelect","order":1,"required":false,"filterable":true,"placeholder":null,"numUnit":null,"options":[{"id":"quiet","label":"Quiet","order":0,"archived":false},{"id":"busy","label":"Busy","order":1,"archived":false},{"id":"packed","label":"Packed","order":2,"archived":false}],"archived":false,"schemaVersion":3},{"propertyDefId":"kh75b789hrwaq3kafenm0xbb6v34gh06","key":"photo_notes","label":"Photo notes","kind":"longSection","order":2,"required":false,"filterable":false,"placeholder":"Lens, framing, where to stand","numUnit":null,"options":[],"archived":false,"schemaVersion":4},{"propertyDefId":"kh7v7h8st8cr913jb2kzb839yxjtpkdf","key":"lens","label":"Lens","kind":"shortLabel","order":3,"required":false,"filterable":false,"placeholder":"16-35 mm","numUnit":null,"options":[],"archived":true,"schemaVersion":6}],"price":{"amountMinor":2900,"currency":"usd"},"spotCount":13,"thumbnailUrl":null,"dashboardUrl":"https://creators.sceniq.earth/products/j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","salesPageUrl":"https://sceniq.earth/mara-lindgren/american-west-first-light","chapterCount":5,"photoCount":31}}}}}},"400":{"description":"Invalid request: invalid_argument","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}},"patch":{"operationId":"update_guide","summary":"Change guide settings (name, headline, tags, country)","description":"Enumerated fields only. Store tags come from the fixed vocabulary (alpine, beaches, city, food, hiking, islands, lakes, photography, road-trips, via-ferrata, waterfalls, wild-camping). Store visibility and putting a guide on sale are dashboard-only; a live guide's content edits reach buyers with publish_changes.","tags":["guides"],"x-scope":"write","x-stability":"stable","x-since":"2026-09-17","x-mcp-tool":"update_guide","parameters":[{"name":"productId","in":"path","required":true,"description":"Id of the guide (a product of type map). From list_guides or create_guide.","schema":{"type":"string","x-sceniq-id":"products"},"example":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"clearThumbnail":{"type":"boolean","description":"true removes the store thumbnail."},"country":{"type":"string","description":"ISO 3166-1 alpha-2 code the guide covers (CH, IT ...); replaces any countries set in the dashboard with this one; empty string means worldwide."},"headline":{"type":"string","description":"One-line promise under the title on the sales page, at most 200 characters."},"name":{"type":"string","description":"Guide title, 1-120 characters."},"purchaseButtonText":{"type":"string","description":"Buy button label, at most 60 characters."},"reviewsShown":{"type":"boolean","description":"Whether buyer reviews show on the store card."},"storeTags":{"type":"array","items":{"type":"string"},"description":"Full replacement list from the fixed store vocabulary."},"thumbnailMediaId":{"type":"string","x-sceniq-id":"media","description":"Id of a product- or listing-owned media row to use as the 4:5 store thumbnail."}},"additionalProperties":false},"examples":{"set_the_headline_store_tags_and_country":{"summary":"Set the headline, store tags and country","value":{"headline":"Twelve viewpoints across Yellowstone and Yosemite, timed for the light and the crowds.","storeTags":["photography","hiking","road-trips"],"country":"US"}},"use_a_guide_photo_as_the_4_5_store_thumbnail":{"summary":"Use a guide photo as the 4:5 store thumbnail","value":{"thumbnailMediaId":"kg7mvr0k3pjqq6p21nr58835y5mtxef0"}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Guide"},"examples":{"set_the_headline_store_tags_and_country":{"summary":"Set the headline, store tags and country","value":{"productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","name":"American West: Parks at First Light","slug":"american-west-first-light","headline":"Twelve viewpoints across Yellowstone and Yosemite, timed for the light and the crowds.","purchaseButtonText":null,"status":"draft","visibleOnStore":false,"storeReviewStatus":null,"storeReviewNote":null,"storeTags":["photography","hiking","road-trips"],"country":"US","reviewsShown":true,"buyerCountShown":false,"pricing":{"oneTimeEnabled":true,"subscriptionIncluded":false,"currency":"usd"},"originalLanguage":"en","createdAt":1789895640000,"updatedAt":1790673240000,"publishedAt":null,"lastApiWriteAt":1790586840000,"region":{"label":"Yellowstone and Yosemite","centerLat":41.2,"centerLon":-115,"defaultZoom":5,"bbox":[-120,37.4,-109.8,45.2]},"areas":[{"id":"area_01m3gvdap06m6mx2kp4t553d6g","name":"Yellowstone National Park","kind":"park","note":"One entrance pass covers every spot in the Yellowstone chapter. Cell coverage is patchy between the geyser basins; download the guide before you drive in.","season":"Most park roads are open to cars from May to early November.","rules":[{"text":"Stay on boardwalks and marked trails in every thermal area.","kind":"other","sourceUrl":"https://www.nps.gov/yell/planyourvisit/safety.htm"}],"fees":[{"label":"Park entrance, private vehicle, 7 days","amount":35,"currency":"USD","per":"vehicle","paidWhere":"online","sourceUrl":"https://www.nps.gov/yell/planyourvisit/fees.htm","checkedOn":"2026-09-20"}],"links":[{"kind":"official","url":"https://www.nps.gov/yell/index.htm","label":"Yellowstone National Park (NPS)"},{"kind":"status","url":"https://www.nps.gov/yell/planyourvisit/conditions.htm","label":"Park road status"}],"sources":[{"url":"https://www.nps.gov/yell/planyourvisit/fees.htm","kind":"page","capturedOn":"2026-09-20","supports":["fees"]}]},{"id":"area_01m3gvgcb04pf38p66vz544w1b","name":"Yosemite National Park","kind":"park","season":"Open all year. Glacier Point Road and Tioga Road close to cars in winter.","rules":[{"text":"Glacier Point Road and Tioga Road are closed to cars in winter, usually from November to late May.","kind":"vehicle","months":[11,12,1,2,3,4,5],"appliesTo":"car","sourceUrl":"https://www.nps.gov/yose/planyourvisit/conditions.htm"}],"fees":[{"label":"Park entrance, private vehicle, 7 days","amount":35,"currency":"USD","per":"vehicle","sourceUrl":"https://www.nps.gov/yose/planyourvisit/fees.htm","checkedOn":"2026-09-20"}],"links":[{"kind":"official","url":"https://www.nps.gov/yose/index.htm","label":"Yosemite National Park (NPS)"},{"kind":"timetable","url":"https://yarts.com/","label":"YARTS buses into the valley"}]}],"mapStyle":null,"propertySchemaVersion":6,"properties":[{"propertyDefId":"kh75t2w9q4r6y8v0j1p3p5a7s9d1f3g5","key":"best_time","label":"Best time","kind":"singleSelect","order":0,"required":false,"filterable":true,"placeholder":null,"numUnit":null,"options":[{"id":"sunrise","label":"Sunrise","order":0,"archived":false},{"id":"morning","label":"Morning","order":1,"archived":false},{"id":"midday","label":"Midday","order":2,"archived":false},{"id":"sunset","label":"Sunset","order":3,"archived":false}],"archived":false,"schemaVersion":2},{"propertyDefId":"kh7b3n5m7q9w1e3r5t7y9v1j3p5p7a9s","key":"crowds","label":"Crowds","kind":"singleSelect","order":1,"required":false,"filterable":true,"placeholder":null,"numUnit":null,"options":[{"id":"quiet","label":"Quiet","order":0,"archived":false},{"id":"busy","label":"Busy","order":1,"archived":false},{"id":"packed","label":"Packed","order":2,"archived":false}],"archived":false,"schemaVersion":3},{"propertyDefId":"kh75b789hrwaq3kafenm0xbb6v34gh06","key":"photo_notes","label":"Photo notes","kind":"longSection","order":2,"required":false,"filterable":false,"placeholder":"Lens, framing, where to stand","numUnit":null,"options":[],"archived":false,"schemaVersion":4},{"propertyDefId":"kh7v7h8st8cr913jb2kzb839yxjtpkdf","key":"lens","label":"Lens","kind":"shortLabel","order":3,"required":false,"filterable":false,"placeholder":"16-35 mm","numUnit":null,"options":[],"archived":true,"schemaVersion":6}],"price":{"amountMinor":2900,"currency":"usd"},"spotCount":13,"thumbnailUrl":null,"dashboardUrl":"https://creators.sceniq.earth/products/j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","salesPageUrl":"https://sceniq.earth/mara-lindgren/american-west-first-light"}},"use_a_guide_photo_as_the_4_5_store_thumbnail":{"summary":"Use a guide photo as the 4:5 store thumbnail","value":{"productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","name":"American West: Parks at First Light","slug":"american-west-first-light","headline":"Twelve viewpoints across Yellowstone and Yosemite, timed for the light and the crowds.","purchaseButtonText":null,"status":"draft","visibleOnStore":false,"storeReviewStatus":null,"storeReviewNote":null,"storeTags":["photography","hiking","road-trips"],"country":"US","reviewsShown":true,"buyerCountShown":false,"pricing":{"oneTimeEnabled":true,"subscriptionIncluded":false,"currency":"usd"},"originalLanguage":"en","createdAt":1789895640000,"updatedAt":1790673240000,"publishedAt":null,"lastApiWriteAt":1790586840000,"region":{"label":"Yellowstone and Yosemite","centerLat":41.2,"centerLon":-115,"defaultZoom":5,"bbox":[-120,37.4,-109.8,45.2]},"areas":[{"id":"area_01m3gvdap06m6mx2kp4t553d6g","name":"Yellowstone National Park","kind":"park","note":"One entrance pass covers every spot in the Yellowstone chapter. Cell coverage is patchy between the geyser basins; download the guide before you drive in.","season":"Most park roads are open to cars from May to early November.","rules":[{"text":"Stay on boardwalks and marked trails in every thermal area.","kind":"other","sourceUrl":"https://www.nps.gov/yell/planyourvisit/safety.htm"}],"fees":[{"label":"Park entrance, private vehicle, 7 days","amount":35,"currency":"USD","per":"vehicle","paidWhere":"online","sourceUrl":"https://www.nps.gov/yell/planyourvisit/fees.htm","checkedOn":"2026-09-20"}],"links":[{"kind":"official","url":"https://www.nps.gov/yell/index.htm","label":"Yellowstone National Park (NPS)"},{"kind":"status","url":"https://www.nps.gov/yell/planyourvisit/conditions.htm","label":"Park road status"}],"sources":[{"url":"https://www.nps.gov/yell/planyourvisit/fees.htm","kind":"page","capturedOn":"2026-09-20","supports":["fees"]}]},{"id":"area_01m3gvgcb04pf38p66vz544w1b","name":"Yosemite National Park","kind":"park","season":"Open all year. Glacier Point Road and Tioga Road close to cars in winter.","rules":[{"text":"Glacier Point Road and Tioga Road are closed to cars in winter, usually from November to late May.","kind":"vehicle","months":[11,12,1,2,3,4,5],"appliesTo":"car","sourceUrl":"https://www.nps.gov/yose/planyourvisit/conditions.htm"}],"fees":[{"label":"Park entrance, private vehicle, 7 days","amount":35,"currency":"USD","per":"vehicle","sourceUrl":"https://www.nps.gov/yose/planyourvisit/fees.htm","checkedOn":"2026-09-20"}],"links":[{"kind":"official","url":"https://www.nps.gov/yose/index.htm","label":"Yosemite National Park (NPS)"},{"kind":"timetable","url":"https://yarts.com/","label":"YARTS buses into the valley"}]}],"mapStyle":null,"propertySchemaVersion":6,"properties":[{"propertyDefId":"kh75t2w9q4r6y8v0j1p3p5a7s9d1f3g5","key":"best_time","label":"Best time","kind":"singleSelect","order":0,"required":false,"filterable":true,"placeholder":null,"numUnit":null,"options":[{"id":"sunrise","label":"Sunrise","order":0,"archived":false},{"id":"morning","label":"Morning","order":1,"archived":false},{"id":"midday","label":"Midday","order":2,"archived":false},{"id":"sunset","label":"Sunset","order":3,"archived":false}],"archived":false,"schemaVersion":2},{"propertyDefId":"kh7b3n5m7q9w1e3r5t7y9v1j3p5p7a9s","key":"crowds","label":"Crowds","kind":"singleSelect","order":1,"required":false,"filterable":true,"placeholder":null,"numUnit":null,"options":[{"id":"quiet","label":"Quiet","order":0,"archived":false},{"id":"busy","label":"Busy","order":1,"archived":false},{"id":"packed","label":"Packed","order":2,"archived":false}],"archived":false,"schemaVersion":3},{"propertyDefId":"kh75b789hrwaq3kafenm0xbb6v34gh06","key":"photo_notes","label":"Photo notes","kind":"longSection","order":2,"required":false,"filterable":false,"placeholder":"Lens, framing, where to stand","numUnit":null,"options":[],"archived":false,"schemaVersion":4},{"propertyDefId":"kh7v7h8st8cr913jb2kzb839yxjtpkdf","key":"lens","label":"Lens","kind":"shortLabel","order":3,"required":false,"filterable":false,"placeholder":"16-35 mm","numUnit":null,"options":[],"archived":true,"schemaVersion":6}],"price":{"amountMinor":2900,"currency":"usd"},"spotCount":13,"thumbnailUrl":"https://quiet-heron-512.convex.cloud/api/storage/parks-store-thumbnail.webp","dashboardUrl":"https://creators.sceniq.earth/products/j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","salesPageUrl":"https://sceniq.earth/mara-lindgren/american-west-first-light"}}}}}},"400":{"description":"Invalid request: invalid_argument, invalid_request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}},"invalid_request":{"summary":"The input was refused","value":{"error":{"code":"invalid_request","message":"A writer refused a value: a map link on a host that is not allowed, a title that is too long, a date that does not exist, too many items in a list. The message is the writer's own sentence."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: api_scope_required, forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"api_scope_required":{"summary":"The key lacks a scope","value":{"error":{"code":"api_scope_required","message":"A read-only key called a write operation, or a key without the publish option called publish_changes."}}},"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"413":{"description":"Too large: payload_too_large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"payload_too_large":{"summary":"The request is too large","value":{"error":{"code":"payload_too_large","message":"A JSON body over 2 MB, an image over 6 MB, a batch upload over 19 MB, or an MCP message over 2 MB."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}}},"/guides/{productId}/region":{"put":{"operationId":"set_guide_region","summary":"Set the map region (label, center, zoom, bbox)","description":"Full replacement of the map region the viewer opens on. Use a label buyers recognise (Yellowstone and Grand Teton), the center of the spots, a zoom of 8-11 for a region, and a bbox [west, south, east, north] that contains every spot.","tags":["guides"],"x-scope":"write","x-stability":"stable","x-since":"2026-09-17","x-mcp-tool":"set_guide_region","parameters":[{"name":"productId","in":"path","required":true,"description":"Id of the guide (a product of type map). From list_guides or create_guide.","schema":{"type":"string","x-sceniq-id":"products"},"example":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"region":{"$ref":"#/components/schemas/MapRegion","description":"Object with label, centerLat, centerLon, defaultZoom (0-22) and bbox [west, south, east, north]."}},"required":["region"],"additionalProperties":false},"examples":{"open_the_map_on_both_parks":{"summary":"Open the map on both parks","value":{"region":{"label":"Yellowstone and Yosemite","centerLat":41.2,"centerLon":-115,"defaultZoom":5,"bbox":[-120,37.4,-109.8,45.2]}}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"const":true,"description":"Always true: the write went through."},"productId":{"type":"string","x-sceniq-id":"products","description":"The guide's id."},"region":{"$ref":"#/components/schemas/MapRegion","description":"The region as sent."}},"required":["ok","productId","region"],"additionalProperties":false},"examples":{"open_the_map_on_both_parks":{"summary":"Open the map on both parks","value":{"ok":true,"productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","region":{"label":"Yellowstone and Yosemite","centerLat":41.2,"centerLon":-115,"defaultZoom":5,"bbox":[-120,37.4,-109.8,45.2]}}}}}}},"400":{"description":"Invalid request: invalid_argument, invalid_request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}},"invalid_request":{"summary":"The input was refused","value":{"error":{"code":"invalid_request","message":"A writer refused a value: a map link on a host that is not allowed, a title that is too long, a date that does not exist, too many items in a list. The message is the writer's own sentence."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: api_scope_required, forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"api_scope_required":{"summary":"The key lacks a scope","value":{"error":{"code":"api_scope_required","message":"A read-only key called a write operation, or a key without the publish option called publish_changes."}}},"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"413":{"description":"Too large: payload_too_large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"payload_too_large":{"summary":"The request is too large","value":{"error":{"code":"payload_too_large","message":"A JSON body over 2 MB, an image over 6 MB, a batch upload over 19 MB, or an MCP message over 2 MB."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}}},"/guides/{productId}/price":{"put":{"operationId":"set_guide_price","summary":"Set the one-time price","description":"Integer minor units (2900 = 29.00) and a 3-letter currency; the floor is 900. Changing the price inserts a new immutable price row. Requires the creator to have accepted the current agreement. Ask the creator for the number, never invent a price.","tags":["guides"],"x-scope":"write","x-stability":"stable","x-since":"2026-09-17","x-mcp-tool":"set_guide_price","parameters":[{"name":"productId","in":"path","required":true,"description":"Id of the guide (a product of type map). From list_guides or create_guide.","schema":{"type":"string","x-sceniq-id":"products"},"example":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"amountMinor":{"type":"number","description":"Price in minor units, integer, at least 900."},"currency":{"type":"string","description":"ISO 4217 code, e.g. usd, chf, eur."}},"required":["amountMinor","currency"],"additionalProperties":false},"examples":{"set_the_price_the_creator_named_29_00_usd":{"summary":"Set the price the creator named (29.00 USD)","value":{"amountMinor":2900,"currency":"usd"}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"const":true,"description":"Always true: the write went through."},"productId":{"type":"string","x-sceniq-id":"products","description":"The guide's id."},"productPriceId":{"type":"string","x-sceniq-id":"productPrices","description":"The new price row (prices are immutable rows)."},"amountMinor":{"type":"number","description":"The price in minor units."},"currency":{"type":"string","description":"ISO 4217 code in lower case."}},"required":["ok","productId","productPriceId","amountMinor","currency"],"additionalProperties":false},"examples":{"set_the_price_the_creator_named_29_00_usd":{"summary":"Set the price the creator named (29.00 USD)","value":{"ok":true,"productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","productPriceId":"kt7z9x7c5v3b1n9m7q5w3e1r9t7y5v3j","amountMinor":2900,"currency":"usd"}}}}}},"400":{"description":"Invalid request: invalid_argument, invalid_request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}},"invalid_request":{"summary":"The input was refused","value":{"error":{"code":"invalid_request","message":"A writer refused a value: a map link on a host that is not allowed, a title that is too long, a date that does not exist, too many items in a list. The message is the writer's own sentence."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: api_scope_required, forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"api_scope_required":{"summary":"The key lacks a scope","value":{"error":{"code":"api_scope_required","message":"A read-only key called a write operation, or a key without the publish option called publish_changes."}}},"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"409":{"description":"The row's state refuses it: agreement_outdated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"agreement_outdated":{"summary":"The agreement needs accepting","value":{"error":{"code":"agreement_outdated","message":"A price change or a publish before the creator accepted the current creator agreement."}}}}}}},"413":{"description":"Too large: payload_too_large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"payload_too_large":{"summary":"The request is too large","value":{"error":{"code":"payload_too_large","message":"A JSON body over 2 MB, an image over 6 MB, a batch upload over 19 MB, or an MCP message over 2 MB."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}}},"/guides/{productId}/readiness":{"get":{"operationId":"get_guide_readiness","summary":"Publish checklist: blocking gates, warnings, review link","description":"Run this before handing the draft back. blocking is the publish gates themselves (agreement, at least one live spot, a pin and a photo on every live spot, a price), the same check publishing enforces. warnings flag coordinate outliers, spots without text, missing credits, an incomplete sales page, facts past their review-by or valid-until dates, dead, parked, spam or redirected links, photos taken far from the pin or before a change at the spot, places far from their spots or in another time zone, stated distances shorter than the straight line, text search map links, dates in the text that have passed, best months missing from a month property, directions that disagree with the pins, best light outside the opening hours and extra pins far from their spot; checks holds the rows behind each warning and every reviewNotes entry. handoff lists the clicks only the creator can make (Publish guide, Publish sales page) with their studio links: plan the hand-off from the start. Send the creator the reviewUrl. For a live guide, see get_publish_status and publish_changes.","tags":["guides"],"x-scope":"read","x-stability":"stable","x-since":"2026-09-17","x-mcp-tool":"get_guide_readiness","parameters":[{"name":"productId","in":"path","required":true,"description":"Id of the guide (a product of type map). From list_guides or create_guide.","schema":{"type":"string","x-sceniq-id":"products"},"example":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Readiness"},"examples":{"a_draft_with_open_publish_gates_and_a_few_warnings":{"summary":"A draft with open publish gates and a few warnings","value":{"productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","name":"American West: Parks at First Light","status":"draft","canPublish":false,"blocking":[{"code":"missing_coordinates","message":"1 spot has no coordinates (Lamar Valley)"},{"code":"missing_photos","message":"2 spots have no photo (Lamar Valley, Taft Point)"}],"warnings":[{"code":"spots_without_text","message":"1 spot(s) have neither a short nor a long description"},{"code":"sales_page_incomplete","message":"Sales page draft: the hero needs between 2 and 6 bullets"},{"code":"no_thumbnail","message":"No store thumbnail set (the creator picks it in the dashboard)"},{"code":"review_due","message":"1 row is past its review-by date; re-check the facts and set a new reviewBy"},{"code":"stale_facts","message":"2 dated facts have run out or not been checked recently (notices, fees, hours, timetables); see checks.staleFacts or list_stale_notices"},{"code":"link_problems","message":"1 link is dead, parked, spam, redirected elsewhere or failing TLS; see checks.links (confirm a false alarm with set_link_verified)"}],"checks":{"staleFacts":[{"kind":"spot","id":"k1736b344br1c7m8qk8ks4sfndxyyftj","name":"Glacier Point","field":"reviewBy","reason":"review_due","date":"2026-09-15","detail":"facts were due for a new check on 2026-09-15"},{"kind":"place","id":"km73j9h5g1f7d3s9a5p1p7j3v9y5t1r7","name":"Old Faithful Inn","field":"schedule","reason":"ended","date":"2026-09-27","detail":"hours valid until 2026-09-27"},{"kind":"route","id":"kx7f2h8j4k0k6z2x8c4v0b6n2m8q4w0e","name":"Fairy Falls trail","field":"status","reason":"ended","date":"2026-09-25","detail":"the closed notice ran until 2026-09-25; update or clear it"}],"reviewNotes":[{"kind":"spot","id":"k1709e2vj4sk8q6x0d3m5r7t9w1y3b5c","name":"Grand Prismatic Spring","note":"The overlook pin comes from your GPX of 18 September; please confirm it. The trail distance is from the NPS page (0.6 mi each way)."},{"kind":"spot","id":"k17rwzt006kbqwjbs5jrqk4jjf5srec9","name":"Lamar Valley","note":"No pin yet: the creator is sending the pullout they use for the bison herds."}],"spotsWithoutSources":7,"links":{"total":26,"flagged":[{"url":"https://www.nps.gov/yose/planyourvisit/glacierpoint.htm","state":"broken","reason":"http_404","finalUrl":null,"usedBy":[{"kind":"spot","name":"Glacier Point","field":"links"}]}],"unverifiable":1,"unchecked":2},"photos":{"farFromPin":[],"judgement":[{"kind":"photo","id":"kg7m9n1b3v5c7x9z1k3k5j7h9g1f3d5s","name":"Tunnel View as a December storm clears","spotId":"k17bc3xz8h6f4d2s0q9w7e5r3t1y2v4j","spotTitle":"Tunnel View","detail":"location rests on judgement, not a geotag or a landmark"}],"beforeChange":[],"nearDuplicates":[]},"places":{"farFromSpots":[],"zoneDiffers":[],"distanceTooShort":[],"searchLinks":[]},"text":{"pastDates":[],"monthMismatch":[],"directions":[]},"light":[],"pins":[],"agreementCurrent":true,"spotCount":12,"archivedSpotCount":1,"missingCoordinates":[{"spotId":"k17rwzt006kbqwjbs5jrqk4jjf5srec9","title":"Lamar Valley"}],"coordinateOutliers":[],"outlierThresholdKm":1590,"outsideRegion":[],"spotsWithoutPhotos":[{"spotId":"k17rwzt006kbqwjbs5jrqk4jjf5srec9","title":"Lamar Valley"},{"spotId":"k17hdgc1c8j423kgq30t9x5hyv1tv8yb","title":"Taft Point"}],"spotsWithoutText":[{"spotId":"k17rwzt006kbqwjbs5jrqk4jjf5srec9","title":"Lamar Valley"}],"photoCount":31,"photosWithoutCredit":0,"price":{"amountMinor":2900,"currency":"usd"},"chapterCount":5,"routeCount":2,"region":{"label":"Yellowstone and Yosemite","centerLat":41.2,"centerLon":-115,"defaultZoom":5,"bbox":[-120,37.4,-109.8,45.2]},"storeTags":["photography","hiking","road-trips"],"country":"US","hasThumbnail":false,"salesPage":{"draftProblems":["the hero needs between 2 and 6 bullets"],"exists":true,"published":false},"lastApiWriteAt":1790586840000},"handoff":{"remaining":["Publish guide: the creator puts the draft on sale in the studio (Publish)","Publish sales page: the creator publishes the sales page draft in the studio"],"studioUrl":"https://creators.sceniq.earth/products/j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","salesPageUrl":"https://creators.sceniq.earth/products/j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2/listing"},"reviewUrl":"https://creators.sceniq.earth/products/j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","nextStep":"Resolve the blocking items, then ask the creator to review the draft in the dashboard"}}}}}},"400":{"description":"Invalid request: invalid_argument","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}}},"/guides/{productId}/stale-notices":{"get":{"operationId":"list_stale_notices","summary":"Dated facts that ran out or need a new check","description":"Status notices past their until date, fees and hours past validUntil, timetables that ran out, events whose dates have all passed, rows past their reviewBy date, and (with olderThanDays) facts not checked in that many days. Each entry names the spot, place, route or area and the field, so you can re-check it and update the row.","tags":["guides"],"x-scope":"read","x-stability":"beta","x-since":"2026-09-30","x-mcp-tool":"list_stale_notices","parameters":[{"name":"productId","in":"path","required":true,"description":"Id of the guide (a product of type map). From list_guides or create_guide.","schema":{"type":"string","x-sceniq-id":"products"},"example":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2"},{"name":"olderThanDays","in":"query","required":false,"description":"Also list statuses, fees, hours and factsCheckedOn older than this many days.","schema":{"type":"number"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaleNotices"},"examples":{"dated_facts_that_ran_out":{"summary":"Dated facts that ran out","value":{"productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","today":"2026-09-29","count":3,"notices":[{"kind":"spot","id":"k1736b344br1c7m8qk8ks4sfndxyyftj","name":"Glacier Point","field":"reviewBy","reason":"review_due","date":"2026-09-15","detail":"facts were due for a new check on 2026-09-15"},{"kind":"place","id":"km73j9h5g1f7d3s9a5p1p7j3v9y5t1r7","name":"Old Faithful Inn","field":"schedule","reason":"ended","date":"2026-09-27","detail":"hours valid until 2026-09-27"},{"kind":"route","id":"kx7f2h8j4k0k6z2x8c4v0b6n2m8q4w0e","name":"Fairy Falls trail","field":"status","reason":"ended","date":"2026-09-25","detail":"the closed notice ran until 2026-09-25; update or clear it"}]}},"also_list_facts_not_checked_in_the_last_180_days":{"summary":"Also list facts not checked in the last 180 days","value":{"productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","today":"2026-09-29","count":4,"notices":[{"kind":"spot","id":"k1736b344br1c7m8qk8ks4sfndxyyftj","name":"Glacier Point","field":"reviewBy","reason":"review_due","date":"2026-09-15","detail":"facts were due for a new check on 2026-09-15"},{"kind":"place","id":"km73j9h5g1f7d3s9a5p1p7j3v9y5t1r7","name":"Old Faithful Inn","field":"schedule","reason":"ended","date":"2026-09-27","detail":"hours valid until 2026-09-27"},{"kind":"route","id":"kx7f2h8j4k0k6z2x8c4v0b6n2m8q4w0e","name":"Fairy Falls trail","field":"status","reason":"ended","date":"2026-09-25","detail":"the closed notice ran until 2026-09-25; update or clear it"},{"kind":"spot","id":"k17hdgc1c8j423kgq30t9x5hyv1tv8yb","name":"Taft Point","field":"factsCheckedOn","reason":"not_checked_recently","date":"2025-10-12","detail":"last checked on 2025-10-12"}]}}}}}},"400":{"description":"Invalid request: invalid_argument","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}}},"/guides/{productId}/properties":{"get":{"operationId":"list_properties","summary":"Custom spot property definitions of a guide","description":"The creator-defined schema every spot's customValues is validated against: key, kind (shortLabel, longSection, number, date, checkbox, singleSelect), required, options with their immutable ids.","tags":["properties"],"x-scope":"read","x-stability":"stable","x-since":"2026-09-17","x-mcp-tool":"list_properties","parameters":[{"name":"productId","in":"path","required":true,"description":"Id of the guide (a product of type map). From list_guides or create_guide.","schema":{"type":"string","x-sceniq-id":"products"},"example":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"productId":{"type":"string","x-sceniq-id":"products","description":"The guide's id."},"schemaVersion":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"The guide's property schema version."},"properties":{"type":"array","items":{"$ref":"#/components/schemas/Property"},"description":"Every property definition, archived ones included."}},"required":["productId","schemaVersion","properties"],"additionalProperties":false},"examples":{"list_a_guide_s_properties_with_their_option_ids":{"summary":"List a guide's properties with their option ids","value":{"productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","schemaVersion":6,"properties":[{"propertyDefId":"kh75t2w9q4r6y8v0j1p3p5a7s9d1f3g5","key":"best_time","label":"Best time","kind":"singleSelect","order":0,"required":false,"filterable":true,"placeholder":null,"numUnit":null,"options":[{"id":"sunrise","label":"Sunrise","order":0,"archived":false},{"id":"morning","label":"Morning","order":1,"archived":false},{"id":"midday","label":"Midday","order":2,"archived":false},{"id":"sunset","label":"Sunset","order":3,"archived":false}],"archived":false,"schemaVersion":2},{"propertyDefId":"kh7b3n5m7q9w1e3r5t7y9v1j3p5p7a9s","key":"crowds","label":"Crowds","kind":"singleSelect","order":1,"required":false,"filterable":true,"placeholder":null,"numUnit":null,"options":[{"id":"quiet","label":"Quiet","order":0,"archived":false},{"id":"busy","label":"Busy","order":1,"archived":false},{"id":"packed","label":"Packed","order":2,"archived":false}],"archived":false,"schemaVersion":3},{"propertyDefId":"kh75b789hrwaq3kafenm0xbb6v34gh06","key":"photo_notes","label":"Photo notes","kind":"longSection","order":2,"required":false,"filterable":false,"placeholder":"Lens, framing, where to stand","numUnit":null,"options":[],"archived":false,"schemaVersion":4},{"propertyDefId":"kh7v7h8st8cr913jb2kzb839yxjtpkdf","key":"lens","label":"Lens","kind":"shortLabel","order":3,"required":false,"filterable":false,"placeholder":"16-35 mm","numUnit":null,"options":[],"archived":true,"schemaVersion":6}]}}}}}},"400":{"description":"Invalid request: invalid_argument","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}},"post":{"operationId":"create_property","summary":"Add a custom property definition","description":"Define a property once, then fill it per spot via customValues[key]. Kinds: shortLabel (one line of text), longSection (titled prose block), number (with numUnit), date (epoch ms), checkbox (multi-select options), singleSelect. The kind decides what buyers can filter by: number, date, checkbox and singleSelect; never shortLabel or longSection, so use singleSelect for a fact buyers should filter on (Effort, Region). Options get server-minted ids; read them back with list_properties before writing spot values. Max 50 live properties per guide.","tags":["properties"],"x-scope":"write","x-stability":"stable","x-since":"2026-09-17","x-mcp-tool":"create_property","parameters":[{"name":"productId","in":"path","required":true,"description":"Id of the guide (a product of type map). From list_guides or create_guide.","schema":{"type":"string","x-sceniq-id":"products"},"example":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"enum":["shortLabel","checkbox","singleSelect","number","date","longSection"],"description":"One of shortLabel, longSection, number, date, checkbox, singleSelect."},"label":{"type":"string","description":"Display label, 1-80 characters (Best time, Difficulty, Parking)."},"filterable":{"type":"boolean","description":"Ignored: the kind decides (see the description)."},"key":{"type":"string","description":"Optional snake_case key; derived from the label when omitted. Immutable."},"numUnit":{"type":"string","description":"Unit label for number kinds (m, km, USD)."},"options":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string","description":"Option label, 1 to 80 characters. The server mints the option's immutable id from it; read the ids back with list_properties."},"order":{"type":"number","description":"Display position (ascending). Absent means the option's index in this list."}},"required":["label"],"additionalProperties":false},"description":"Required for checkbox and singleSelect, refused for other kinds: 1 to 100 options [{ label, order? }] in display order."},"placeholder":{"type":"string","description":"Editor placeholder text."},"required":{"type":"boolean","description":"Whether every spot must carry a value."}},"required":["kind","label"],"additionalProperties":false},"examples":{"a_single_select_buyers_can_filter_by":{"summary":"A single select buyers can filter by","value":{"label":"Best time","kind":"singleSelect","options":[{"label":"Sunrise"},{"label":"Morning"},{"label":"Midday"},{"label":"Sunset"}]}},"a_long_section_its_own_block_on_the_spot_page_never_a_filter":{"summary":"A long section: its own block on the spot page, never a filter","value":{"label":"Photo notes","kind":"longSection","placeholder":"Lens, framing, where to stand"}}}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Property"},"examples":{"a_single_select_buyers_can_filter_by":{"summary":"A single select buyers can filter by","value":{"propertyDefId":"kh75t2w9q4r6y8v0j1p3p5a7s9d1f3g5","key":"best_time","label":"Best time","kind":"singleSelect","order":0,"required":false,"filterable":true,"placeholder":null,"numUnit":null,"options":[{"id":"sunrise","label":"Sunrise","order":0,"archived":false},{"id":"morning","label":"Morning","order":1,"archived":false},{"id":"midday","label":"Midday","order":2,"archived":false},{"id":"sunset","label":"Sunset","order":3,"archived":false}],"archived":false,"schemaVersion":2}},"a_long_section_its_own_block_on_the_spot_page_never_a_filter":{"summary":"A long section: its own block on the spot page, never a filter","value":{"propertyDefId":"kh75b789hrwaq3kafenm0xbb6v34gh06","key":"photo_notes","label":"Photo notes","kind":"longSection","order":2,"required":false,"filterable":false,"placeholder":"Lens, framing, where to stand","numUnit":null,"options":[],"archived":false,"schemaVersion":4}}}}}},"400":{"description":"Invalid request: invalid_argument, invalid_request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}},"invalid_request":{"summary":"The input was refused","value":{"error":{"code":"invalid_request","message":"A writer refused a value: a map link on a host that is not allowed, a title that is too long, a date that does not exist, too many items in a list. The message is the writer's own sentence."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: api_scope_required, forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"api_scope_required":{"summary":"The key lacks a scope","value":{"error":{"code":"api_scope_required","message":"A read-only key called a write operation, or a key without the publish option called publish_changes."}}},"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"413":{"description":"Too large: payload_too_large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"payload_too_large":{"summary":"The request is too large","value":{"error":{"code":"payload_too_large","message":"A JSON body over 2 MB, an image over 6 MB, a batch upload over 19 MB, or an MCP message over 2 MB."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}}},"/properties/{propertyDefId}":{"patch":{"operationId":"update_property","summary":"Relabel a property or manage its options","description":"Key and kind are immutable (a type change is a new property). options is the full desired list: entries with an id relabel, reorder or archive an existing option; entries without an id are new. Existing option ids can never be removed, only archived.","tags":["properties"],"x-scope":"write","x-stability":"stable","x-since":"2026-09-17","x-mcp-tool":"update_property","parameters":[{"name":"propertyDefId","in":"path","required":true,"description":"Id of the property definition (from list_properties).","schema":{"type":"string","x-sceniq-id":"propertyDefs"},"example":"kh75t2w9q4r6y8v0j1p3p5a7s9d1f3g5"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"filterable":{"type":"boolean","description":"Ignored: the kind decides (see create_property)."},"label":{"type":"string","description":"Display label, 1 to 80 characters."},"numUnit":{"type":"string","description":"Unit label for number properties (m, km, USD); refused on other kinds."},"options":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"An existing option's id, to relabel, reorder or archive it. Leave it out for a new option; the server mints its id. Every existing id must stay in the list."},"label":{"type":"string","description":"Option label, 1 to 80 characters."},"order":{"type":"number","description":"Display position (ascending). Absent keeps an existing option's position; a new option takes its index in this list."},"archived":{"type":"boolean","description":"true retires the option: filters drop it at once, stored spot values keep it. false brings it back; spots already holding it return to its filter once their customValues are written again. Absent keeps the current state."}},"required":["label"],"additionalProperties":false},"description":"Full list, at most 100: [{ id?, label, order?, archived? }]."},"placeholder":{"type":"string","description":"Editor placeholder text, stored as sent."},"required":{"type":"boolean","description":"Whether every spot must carry a value. Checked when a spot is created and whenever a spot's customValues are sent."}},"additionalProperties":false},"examples":{"add_an_option_the_existing_ones_keep_their_ids":{"summary":"Add an option; the existing ones keep their ids","value":{"options":[{"id":"sunrise","label":"Sunrise"},{"id":"morning","label":"Morning"},{"id":"midday","label":"Midday"},{"id":"sunset","label":"Sunset"},{"label":"Night"}]}},"relabel_a_property_and_one_of_its_options_stored_values_stay":{"summary":"Relabel a property and one of its options; stored values stay","value":{"label":"Crowds in summer","options":[{"id":"quiet","label":"Quiet"},{"id":"busy","label":"Busy"},{"id":"packed","label":"Very busy"}]}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"const":true,"description":"Always true: the write went through."},"propertyDefId":{"type":"string","x-sceniq-id":"propertyDefs","description":"The property's id."},"schemaVersion":{"type":"number","description":"The guide's property schema version after the change."}},"required":["ok","propertyDefId","schemaVersion"],"additionalProperties":false},"examples":{"add_an_option_the_existing_ones_keep_their_ids":{"summary":"Add an option; the existing ones keep their ids","value":{"ok":true,"propertyDefId":"kh75t2w9q4r6y8v0j1p3p5a7s9d1f3g5","schemaVersion":7}},"relabel_a_property_and_one_of_its_options_stored_values_stay":{"summary":"Relabel a property and one of its options; stored values stay","value":{"ok":true,"propertyDefId":"kh7b3n5m7q9w1e3r5t7y9v1j3p5p7a9s","schemaVersion":8}}}}}},"400":{"description":"Invalid request: invalid_argument, invalid_request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}},"invalid_request":{"summary":"The input was refused","value":{"error":{"code":"invalid_request","message":"A writer refused a value: a map link on a host that is not allowed, a title that is too long, a date that does not exist, too many items in a list. The message is the writer's own sentence."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: api_scope_required, forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"api_scope_required":{"summary":"The key lacks a scope","value":{"error":{"code":"api_scope_required","message":"A read-only key called a write operation, or a key without the publish option called publish_changes."}}},"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"413":{"description":"Too large: payload_too_large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"payload_too_large":{"summary":"The request is too large","value":{"error":{"code":"payload_too_large","message":"A JSON body over 2 MB, an image over 6 MB, a batch upload over 19 MB, or an MCP message over 2 MB."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}}},"/properties/{propertyDefId}/convert":{"post":{"operationId":"convert_property","summary":"Change a property's kind without losing values","description":"The kind changes that keep every stored value: singleSelect to checkbox (each value becomes a one-item list), checkbox to singleSelect (refused while any spot holds more than one option), shortLabel to longSection and back (long to short only when every value fits one line). Use it when one answer per spot turns out to be too few (entry free on foot but a timed car park booking). Any other change is a new property plus archive_property on the old one. For a one-line qualifier next to a value, use update_spot customNotes instead.","tags":["properties"],"x-scope":"write","x-stability":"beta","x-since":"2026-09-30","x-mcp-tool":"convert_property","parameters":[{"name":"propertyDefId","in":"path","required":true,"description":"Id of the property definition (from list_properties).","schema":{"type":"string","x-sceniq-id":"propertyDefs"},"example":"kh75t2w9q4r6y8v0j1p3p5a7s9d1f3g5"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"toKind":{"enum":["shortLabel","checkbox","singleSelect","number","date","longSection"],"description":"The new kind: checkbox, singleSelect, shortLabel or longSection (see the allowed pairs above)."}},"required":["toKind"],"additionalProperties":false},"examples":{"let_a_spot_hold_more_than_one_best_time_single_select_to_checkbox":{"summary":"Let a spot hold more than one best time (single select to checkbox)","value":{"toKind":"checkbox"}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"const":true,"description":"Always true: the write went through."},"propertyDefId":{"type":"string","x-sceniq-id":"propertyDefs","description":"The property's id."},"kind":{"type":"string","description":"The property's new kind."},"schemaVersion":{"type":"number","description":"The guide's property schema version after the change."},"spotsChanged":{"type":"number","description":"Spots whose stored value changed shape."}},"required":["ok","propertyDefId","kind","schemaVersion","spotsChanged"],"additionalProperties":false},"examples":{"let_a_spot_hold_more_than_one_best_time_single_select_to_checkbox":{"summary":"Let a spot hold more than one best time (single select to checkbox)","value":{"ok":true,"propertyDefId":"kh75t2w9q4r6y8v0j1p3p5a7s9d1f3g5","kind":"checkbox","schemaVersion":9,"spotsChanged":12}}}}}},"400":{"description":"Invalid request: invalid_argument, invalid_request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}},"invalid_request":{"summary":"The input was refused","value":{"error":{"code":"invalid_request","message":"A writer refused a value: a map link on a host that is not allowed, a title that is too long, a date that does not exist, too many items in a list. The message is the writer's own sentence."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: api_scope_required, forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"api_scope_required":{"summary":"The key lacks a scope","value":{"error":{"code":"api_scope_required","message":"A read-only key called a write operation, or a key without the publish option called publish_changes."}}},"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"413":{"description":"Too large: payload_too_large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"payload_too_large":{"summary":"The request is too large","value":{"error":{"code":"payload_too_large","message":"A JSON body over 2 MB, an image over 6 MB, a batch upload over 19 MB, or an MCP message over 2 MB."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}}},"/properties/{propertyDefId}/archive":{"post":{"operationId":"archive_property","summary":"Archive a property (values on spots are preserved)","description":"Removes the property from the editor and every filter. Stored spot values stay as inert legacy data. Keys are reserved forever.","tags":["properties"],"x-scope":"write","x-stability":"stable","x-since":"2026-09-17","x-mcp-tool":"archive_property","parameters":[{"name":"propertyDefId","in":"path","required":true,"description":"Id of the property definition.","schema":{"type":"string","x-sceniq-id":"propertyDefs"},"example":"kh7v7h8st8cr913jb2kzb839yxjtpkdf"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"const":true,"description":"Always true: the write went through."},"propertyDefId":{"type":"string","x-sceniq-id":"propertyDefs","description":"The property's id."},"archived":{"const":true,"description":"Always true: the property is archived."}},"required":["ok","propertyDefId","archived"],"additionalProperties":false},"examples":{"archive_a_property_spot_values_stay_stored":{"summary":"Archive a property; spot values stay stored","value":{"ok":true,"propertyDefId":"kh7v7h8st8cr913jb2kzb839yxjtpkdf","archived":true}}}}}},"400":{"description":"Invalid request: invalid_argument, invalid_request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}},"invalid_request":{"summary":"The input was refused","value":{"error":{"code":"invalid_request","message":"A writer refused a value: a map link on a host that is not allowed, a title that is too long, a date that does not exist, too many items in a list. The message is the writer's own sentence."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: api_scope_required, forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"api_scope_required":{"summary":"The key lacks a scope","value":{"error":{"code":"api_scope_required","message":"A read-only key called a write operation, or a key without the publish option called publish_changes."}}},"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"413":{"description":"Too large: payload_too_large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"payload_too_large":{"summary":"The request is too large","value":{"error":{"code":"payload_too_large","message":"A JSON body over 2 MB, an image over 6 MB, a batch upload over 19 MB, or an MCP message over 2 MB."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}}},"/guides/{productId}/properties/order":{"put":{"operationId":"reorder_properties","summary":"Set the display order of all live properties","description":"orderedIds must list EXACTLY the guide's live (non-archived) property ids.","tags":["properties"],"x-scope":"write","x-stability":"stable","x-since":"2026-09-17","x-mcp-tool":"reorder_properties","parameters":[{"name":"productId","in":"path","required":true,"description":"Id of the guide (a product of type map). From list_guides or create_guide.","schema":{"type":"string","x-sceniq-id":"products"},"example":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"orderedIds":{"type":"array","items":{"type":"string","x-sceniq-id":"propertyDefs"},"description":"All live property ids in the desired order."}},"required":["orderedIds"],"additionalProperties":false},"examples":{"put_crowds_first_every_live_property_in_the_new_order":{"summary":"Put Crowds first (every live property, in the new order)","value":{"orderedIds":["kh7b3n5m7q9w1e3r5t7y9v1j3p5p7a9s","kh75t2w9q4r6y8v0j1p3p5a7s9d1f3g5","kh75b789hrwaq3kafenm0xbb6v34gh06"]}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"const":true,"description":"Always true: the write went through."},"productId":{"type":"string","x-sceniq-id":"products","description":"The guide's id."},"schemaVersion":{"type":"number","description":"The guide's property schema version after the change."}},"required":["ok","productId","schemaVersion"],"additionalProperties":false},"examples":{"put_crowds_first_every_live_property_in_the_new_order":{"summary":"Put Crowds first (every live property, in the new order)","value":{"ok":true,"productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","schemaVersion":10}}}}}},"400":{"description":"Invalid request: invalid_argument, invalid_request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}},"invalid_request":{"summary":"The input was refused","value":{"error":{"code":"invalid_request","message":"A writer refused a value: a map link on a host that is not allowed, a title that is too long, a date that does not exist, too many items in a list. The message is the writer's own sentence."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: api_scope_required, forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"api_scope_required":{"summary":"The key lacks a scope","value":{"error":{"code":"api_scope_required","message":"A read-only key called a write operation, or a key without the publish option called publish_changes."}}},"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"413":{"description":"Too large: payload_too_large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"payload_too_large":{"summary":"The request is too large","value":{"error":{"code":"payload_too_large","message":"A JSON body over 2 MB, an image over 6 MB, a batch upload over 19 MB, or an MCP message over 2 MB."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}}},"/guides/{productId}/spots":{"get":{"operationId":"list_spots","summary":"All spots of a guide in editor order","description":"Includes archived spots (flagged). Each spot carries its spotKey, which chapters and routes reference.","tags":["spots"],"x-scope":"read","x-stability":"stable","x-since":"2026-09-17","x-mcp-tool":"list_spots","parameters":[{"name":"productId","in":"path","required":true,"description":"Id of the guide (a product of type map). From list_guides or create_guide.","schema":{"type":"string","x-sceniq-id":"products"},"example":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"productId":{"type":"string","x-sceniq-id":"products","description":"The guide's id."},"spots":{"type":"array","items":{"$ref":"#/components/schemas/Spot"},"description":"Every spot in editor order, archived ones included."}},"required":["productId","spots"],"additionalProperties":false},"examples":{"list_the_spots_of_a_guide":{"summary":"List the spots of a guide","value":{"productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","spots":[{"spotId":"k1709e2vj4sk8q6x0d3m5r7t9w1y3b5c","spotKey":"01M2Z1G0Y0QG7M2V6N9R3T5W8Y","productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","title":"Grand Prismatic Spring","kicker":"Yellowstone, Midway Geyser Basin","lat":44.5251,"lon":-110.8382,"mapsUrl":"https://maps.apple.com/?ll=44.5251,-110.8382&q=Grand%20Prismatic%20Spring","shortDescription":"The largest hot spring in the United States. See it from the boardwalk, then from the overlook above the Fairy Falls trail.","longDescription":"Grand Prismatic is about 110 meters across, and from the boardwalk you mostly see steam and the orange mats that run off toward the Firehole River. For the colors, park at the Fairy Falls trailhead and follow the trail to the signed spur for the overlook: about 1 km each way, 20 minutes up. The whole spring opens up below the platform. Come on a warm, dry morning; on a cold day the steam hides everything.","color":null,"cardOrientation":"landscape","customValues":{"best_time":"morning","crowds":"packed","photo_notes":"From the overlook a 24 mm lens takes in the whole spring. On the boardwalk, shoot the runoff channels instead of the steam."},"tripFacts":{"elevationM":2176,"elevationRefersTo":"ground","busyness":5,"bestSeason":"Late May to September"},"arrival":{"byCar":{"directions":"Grand Loop Road, 11 km north of Old Faithful. Midway Geyser Basin lot.","parking":"Midway Geyser Basin lot, full by 10:00 in summer. Fairy Falls trailhead lot 1.6 km south.","walkToSpotMin":10},"byTrainBus":{"none":true},"bestTime":"Mid morning on a warm, dry day: cold air turns the steam into fog that hides the colors."},"mapLinks":[],"imagesEnabled":true,"customPropsEnabled":true,"archived":false,"ref":null,"accessMode":"short_walk","pinLabel":null,"pins":[{"kind":"viewpoint","label":"Grand Prismatic Overlook","lat":44.5192,"lon":-110.8391,"note":"Platform on a spur of the Fairy Falls trail, about 1 km from the trailhead lot."},{"kind":"parking","label":"Fairy Falls trailhead lot","lat":44.5153,"lon":-110.8325,"note":"For the overlook. Full by mid morning in July and August."}],"links":[{"kind":"official","url":"https://www.nps.gov/places/000/grand-prismatic-spring.htm","label":"Grand Prismatic Spring (NPS)"},{"kind":"status","url":"https://www.nps.gov/yell/planyourvisit/conditions.htm","label":"Park road status"}],"status":null,"fees":[],"schedule":null,"features":[],"restrictions":[{"kind":"no_drone","label":"No drones in the park","note":"Drones are banned in all US national parks."},{"kind":"no_entry","label":"Stay on the boardwalk","note":"The crust around the spring is thin, and the water under it is scalding."}],"events":[],"food":null,"areaId":"area_01m3gvdap06m6mx2kp4t553d6g","timeZone":"America/Denver","timeZoneManual":false,"customNotes":{"crowds":"Quieter before 9:00 and after 18:00"},"sources":[{"url":"https://www.nps.gov/places/000/grand-prismatic-spring.htm","kind":"page","capturedOn":"2026-09-20","supports":["arrival","restrictions"]}],"reviewNotes":"The overlook pin comes from your GPX of 18 September; please confirm it. The trail distance is from the NPS page (0.6 mi each way).","factsCheckedOn":"2026-09-20","reviewBy":"2027-04-01","siteChange":null,"createdAt":1789895640000,"updatedAt":1790586840000},{"spotId":"k17bc3xz8h6f4d2s0q9w7e5r3t1y2v4j","spotKey":"01M2Z1G0Y0R2K5P8S1V4X7Z0C3","productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","title":"Tunnel View","kicker":"Yosemite Valley","lat":37.7156,"lon":-119.677,"mapsUrl":"https://www.google.com/maps/search/?api=1&query=37.7156,-119.677","shortDescription":"El Capitan, Half Dome and Bridalveil Fall in one frame, at the east end of the Wawona Tunnel.","longDescription":null,"color":null,"cardOrientation":"landscape","customValues":{"best_time":"sunset","crowds":"busy"},"tripFacts":null,"arrival":{"byCar":{"directions":"Wawona Road (Highway 41), at the east end of the Wawona Tunnel.","parking":"Lots on both sides of the road; the north lot fills first at sunset.","walkToSpotMin":1},"bestTime":"The hour before sunset, or when a winter storm starts to clear."},"mapLinks":[],"imagesEnabled":true,"customPropsEnabled":true,"archived":false,"ref":"yose-tunnel-view","accessMode":"drive_up","pinLabel":null,"pins":[],"links":[],"status":null,"fees":[],"schedule":null,"features":[],"restrictions":[],"events":[],"food":null,"areaId":"area_01m3gvgcb04pf38p66vz544w1b","timeZone":"America/Los_Angeles","timeZoneManual":false,"customNotes":{},"sources":[],"reviewNotes":null,"factsCheckedOn":null,"reviewBy":null,"siteChange":null,"createdAt":1789895640000,"updatedAt":1790586840000},{"spotId":"k17rwzt006kbqwjbs5jrqk4jjf5srec9","spotKey":"01M3GYV6A0Y3SYC62RBPEA9S0C","productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","title":"Lamar Valley","kicker":"Yellowstone, northeast entrance road","lat":null,"lon":null,"mapsUrl":null,"shortDescription":null,"longDescription":null,"color":null,"cardOrientation":"landscape","customValues":{},"tripFacts":null,"arrival":null,"mapLinks":[],"imagesEnabled":true,"customPropsEnabled":true,"archived":false,"ref":null,"accessMode":null,"pinLabel":null,"pins":[],"links":[],"status":null,"fees":[],"schedule":null,"features":[],"restrictions":[],"events":[],"food":null,"areaId":null,"timeZone":null,"timeZoneManual":false,"customNotes":{},"sources":[],"reviewNotes":"No pin yet: the creator is sending the pullout they use for the bison herds.","factsCheckedOn":null,"reviewBy":null,"siteChange":null,"createdAt":1789895640000,"updatedAt":1789895640000}]}}}}}},"400":{"description":"Invalid request: invalid_argument","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}},"post":{"operationId":"create_spot","summary":"Add a spot (a place the creator has been to)","description":"Coordinates come from the creator (their map link, GPX, or a pin they confirm) or, for a guide the creator asked you to research, from a source you cite in sources; never from memory. Leave lat/lon empty rather than guessing; the readiness check will list what is missing. Titles are place names as locals know them; kicker is the short line above the title (region, type). customValues keys must match list_properties; option values use option ids, not labels. create_spot takes every field update_spot takes (arrival, mapLinks, tripFacts, accessMode, pins, links, status, fees, schedule and the rest), so one call makes a complete spot. For many spots, or re-runs that must not duplicate, use upsert_spots. The response carries warnings (an http link) that did not stop the write.","tags":["spots"],"x-scope":"write","x-stability":"stable","x-since":"2026-09-17","x-mcp-tool":"create_spot","parameters":[{"name":"productId","in":"path","required":true,"description":"Id of the guide (a product of type map). From list_guides or create_guide.","schema":{"type":"string","x-sceniq-id":"products"},"example":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","description":"Place name as locals know it, e.g. Oeschinensee or Fushimi Inari-taisha. Cannot be empty."},"accessMode":{"anyOf":[{"enum":["drive_up","short_walk","hike","multi_day","boat","cable_car","train","flight","tour_only","aerial_only"]},{"type":"null"}],"description":"How visitors reach the spot, shown as Accessibility: drive_up, short_walk, hike, multi_day, boat, cable_car, train, flight, tour_only, aerial_only. null clears. Without it the cell shows the easiest required route's grade, or Drive-up only when arrival.byCar describes a drive."},"areaId":{"type":"string","description":"The area (park, island, region) the spot sits in, from set_area; its rules, fees and links show on the spot. Empty string clears."},"arrival":{"anyOf":[{"$ref":"#/components/schemas/Arrival"},{"type":"null"}],"description":"How to get there, full replacement, null clears: { byCar?: { directions, parking, walkToSpotMin, walkRoundTrip? (the minutes are there and back), none? (no car access), note? }, byTrainBus?: { route, walkFromStopMin, walkRoundTrip?, none? (no public transport, which reads differently from an empty field), note? }, byBoat?, byAir?: { airports? (IATA or ICAO codes), route?, minutes?, operatorUrl?, luggageKg?, none?, note? }, onFoot?: { route?, minutes?, roundTrip?, none?, note? }, byBike?: { same }, bestTime?, operating?, approaches?: [{ label (Argentine side), country? (AR), legs?: [{ mode: car|bus|train|tram|metro|cable_car|funicular|boat|ferry|plane|helicopter|shuttle|jeep|walk|bike|taxi|other, from?, to?, minutes?, roundTrip?, price?, payment?, note? }], hours?, entry?, note?, lat?, lon? }] (at most 6, for spots with several ways in or chains of legs), rules?: [{ text, kind?: reservation|permit|guide|registration|no_independent_travel|vehicle|other, months? [1-12] (shown only then), appliesTo?: car|all, bookingOpens?, sourceUrl? }] }."},"cardOrientation":{"enum":["portrait","landscape"],"description":"portrait or landscape (photo framing in the viewer); a spot without one reads as landscape."},"color":{"type":"string","description":"Optional pin color hex, e.g. #0071e3. Empty string clears."},"customNotes":{"type":"object","additionalProperties":{"type":"string"},"description":"One short note per custom property value, keyed by property key, shown next to the value (walls 40 EUR, morning from viewpoint 7). Full replacement ({} clears)."},"customPropsEnabled":{"type":"boolean","description":"false hides custom properties from buyers; values stay stored."},"customValues":{"type":"object","additionalProperties":{},"description":"Object keyed by property key (list_properties): text for shortLabel and longSection, a number for number, epoch ms for date, one option id for singleSelect, an array of option ids for checkbox (ids, never labels). Every required property needs a value; keys without a live property are kept unchecked. Sent for an existing spot it replaces the stored object; null for a key clears that value."},"events":{"type":"array","items":{"$ref":"#/components/schemas/SpotEvent"},"description":"Recurring or one-off events worth timing a visit for, full replacement, at most 12: [{ name, when (in words: every night at 19:45 and 20:45), dates? [YYYY-MM-DD] (the apps show the next one), months?, url?, free?, note? }]."},"factsCheckedOn":{"type":"string","description":"The day the facts were last checked against their sources (YYYY-MM-DD). Empty string clears."},"features":{"type":"array","items":{"$ref":"#/components/schemas/SpotFeature"},"description":"Parts of the site with their own rules (a monastery's closing day, a ticketed skyway), full replacement, at most 12: [{ name, note?, hours?, entry?, season?, fees? (as fees), status? (as status), url? }]."},"fees":{"type":"array","items":{"$ref":"#/components/schemas/Fee"},"description":"Fees and tickets, full replacement ([] clears), at most 30: [{ label, amount? (major units, e.g. 40 or 12.5; needs currency), currency? (EUR), free?, seeOfficial? (a price left to the official page on purpose), per?: person|vehicle|night|group|entry|day|hour, audience?: all|adult|child|foreign|domestic|resident|student|senior, paidWhere?: online|on_site|in_tour, payment?: cash_only|card_only|cash_or_card, note?, validFrom?, validUntil?, sourceUrl?, checkedOn? }]. Buyers see the amount with an as-of date; readiness flags rows past validUntil or unchecked for a year."},"food":{"anyOf":[{"$ref":"#/components/schemas/FoodNote"},{"type":"null"}],"description":"Why the spot lists no food places, null clears: { status: included (meals come with the lodge or boat) | none_nearby | bring_your_own, note? }."},"imagesEnabled":{"type":"boolean","description":"false hides the photo section from buyers; photos stay stored."},"kicker":{"type":"string","description":"Short eyebrow above the title, e.g. Patagonia, Bernese Oberland or Glacier lake. Empty string clears."},"lat":{"type":"number","description":"Latitude in decimal degrees (-90 to 90). From the creator's material or a cited source."},"links":{"type":"array","items":{"$ref":"#/components/schemas/GuideLink"},"description":"Links with a purpose, full replacement ([] clears), at most 12: [{ kind: official|website|tickets|booking|status|timetable|tide|listing|social|authority|app|other, label?, url? (http or https; http is accepted with a warning), value? (a channel that is not a URL, e.g. WeChat mini program: Li River boats), note? }]. Each needs a url or a value."},"lon":{"type":"number","description":"Longitude in decimal degrees (-180 to 180)."},"longDescription":{"type":"string","description":"The full write-up in the creator's voice. Empty string clears."},"mapLinks":{"type":"array","items":{"$ref":"#/components/schemas/MapLink"},"description":"Extra map links [{ label, url }] (https or an allowlisted map link), drawn as map pills. [] clears. For official, ticket or status pages use links instead."},"mapsUrl":{"type":"string","description":"The creator's own map link: https on Google Maps, Apple Maps, Swisstopo, OpenStreetMap or SchweizMobil, or a geo: URI. Empty string clears."},"pinLabel":{"type":"string","description":"What the main pin marks for a spot that is an area or a line, shown as Pinned: <label> (Ti Top viewpoint). Empty string clears."},"pins":{"type":"array","items":{"$ref":"#/components/schemas/SpotPin"},"description":"Extra points, full replacement ([] clears), at most 12: [{ kind: viewpoint|entrance|gate|trailhead|parking|stop|pier|summit|other, label, lat, lon, months? [1-12] (only reachable then), note? }]. Each gets its own map links and a place on the web map."},"ref":{"type":"string","description":"Your own stable key for this spot (af04-abu-simbel), unique in the guide; upsert_spots matches on it. Empty string clears."},"restrictions":{"type":"array","items":{"$ref":"#/components/schemas/Restriction"},"description":"Rules on site, full replacement, at most 20: [{ kind: no_photo|wide_only|no_drone|no_entry|no_stopping|no_parking|other, label, note?, lat?, lon?, radiusM?, line? ([[lon, lat], ...] for a stretch of road), sourceUrl? }]."},"reviewBy":{"type":"string","description":"The day the facts need a new check (YYYY-MM-DD), e.g. when a season, fare or timetable runs out. get_guide_readiness and get_publish_status warn once it has passed. Empty string clears."},"reviewNotes":{"type":"string","description":"Notes for the creator's review (why a value was chosen, what could not be verified). Never shown to buyers; get_guide_readiness lists them. Empty string clears."},"schedule":{"anyOf":[{"$ref":"#/components/schemas/Schedule"},{"type":"null"}],"description":"Structured opening hours, null clears; the free-text hours stay the fallback: { hours?: [{ from? (MM-DD), to? (MM-DD, may wrap over the new year), weekdays? [1-7], closed?, open? (HH:MM or sunrise|sunset), close? (HH:MM or sunrise|sunset), openOffsetMin?, closeOffsetMin? (minutes around a sun anchor, -60 = an hour before), lastEntry? (HH:MM), leaveBy? (HH:MM), note? }], specialDays?: [{ date? or rule? (first Sunday of the month), closed?, open?, close?, note? }], slots?: { first, last, everyMin, cap?, note? }, validFrom?, validUntil?, sourceUrl?, checkedOn?, note? }. The last matching band wins, so list the year-round band first and exceptions after it. The apps show today's hours in the spot's time zone."},"shortDescription":{"type":"string","description":"One or two sentences for the card. Empty string clears."},"siteChange":{"anyOf":[{"$ref":"#/components/schemas/SiteChange"},{"type":"null"}],"description":"The day something at the spot changed (a bridge replaced, boats banned), null clears: { on (YYYY-MM-DD), note? }. Readiness flags photos captured before it."},"sources":{"type":"array","items":{"$ref":"#/components/schemas/SourceRef"},"description":"Research evidence for reviewers, never shown to buyers; full replacement, at most 40: [{ url? or title?, kind?: page|api|archive|document|other, capturedOn?, note?, supports? (which facts it backs, e.g. fees, arrival.operating, lat/lon), conflict? (true when it disagrees with another source on those facts) }]."},"status":{"anyOf":[{"$ref":"#/components/schemas/StatusNotice"},{"type":"null"}],"description":"Closure or works notice, null clears: { state: open|partly_closed|closed|reopening, note?, since?, until? (the day the state is expected to end; buyers stop seeing the notice after it), sourceUrl?, checkedOn? }. reopening with until means reopens on that day."},"timeZone":{"type":"string","description":"IANA zone (America/Phoenix). Derived from the pin on every write; set it only when the lookup is wrong near a border. Empty string hands it back to the pin."},"tripFacts":{"anyOf":[{"$ref":"#/components/schemas/TripFacts"},{"type":"null"}],"description":"The planning stats bar, null clears: { elevationM? (meters; 0 is a stated sea level, absent is unknown), elevationRefersTo?: viewpoint|summit|ground|water|trailhead, elevationSource?, busyness? (1 quiet to 5 packed, shown as Crowdedness), bestSeason? }."}},"required":["title"],"additionalProperties":false},"examples":{"create_a_complete_spot_in_one_call":{"summary":"Create a complete spot in one call","value":{"title":"Grand Prismatic Spring","kicker":"Yellowstone, Midway Geyser Basin","lat":44.5251,"lon":-110.8382,"mapsUrl":"https://maps.apple.com/?ll=44.5251,-110.8382&q=Grand%20Prismatic%20Spring","shortDescription":"The largest hot spring in the United States. See it from the boardwalk, then from the overlook above the Fairy Falls trail.","longDescription":"Grand Prismatic is about 110 meters across, and from the boardwalk you mostly see steam and the orange mats that run off toward the Firehole River. For the colors, park at the Fairy Falls trailhead and follow the trail to the signed spur for the overlook: about 1 km each way, 20 minutes up. The whole spring opens up below the platform. Come on a warm, dry morning; on a cold day the steam hides everything.","accessMode":"short_walk","tripFacts":{"elevationM":2176,"elevationRefersTo":"ground","busyness":5,"bestSeason":"Late May to September"},"arrival":{"byCar":{"directions":"Grand Loop Road, 11 km north of Old Faithful. Midway Geyser Basin lot.","parking":"Midway Geyser Basin lot, full by 10:00 in summer. Fairy Falls trailhead lot 1.6 km south.","walkToSpotMin":10},"byTrainBus":{"none":true},"bestTime":"Mid morning on a warm, dry day: cold air turns the steam into fog that hides the colors."},"pins":[{"kind":"viewpoint","label":"Grand Prismatic Overlook","lat":44.5192,"lon":-110.8391,"note":"Platform on a spur of the Fairy Falls trail, about 1 km from the trailhead lot."},{"kind":"parking","label":"Fairy Falls trailhead lot","lat":44.5153,"lon":-110.8325,"note":"For the overlook. Full by mid morning in July and August."}],"fees":[{"label":"Park entrance, private vehicle, 7 days","amount":35,"currency":"USD","per":"vehicle","paidWhere":"online","sourceUrl":"https://www.nps.gov/yell/planyourvisit/fees.htm","checkedOn":"2026-09-20"}],"restrictions":[{"kind":"no_drone","label":"No drones in the park","note":"Drones are banned in all US national parks."},{"kind":"no_entry","label":"Stay on the boardwalk","note":"The crust around the spring is thin, and the water under it is scalding."}],"links":[{"kind":"official","url":"https://www.nps.gov/places/000/grand-prismatic-spring.htm","label":"Grand Prismatic Spring (NPS)"},{"kind":"status","url":"https://www.nps.gov/yell/planyourvisit/conditions.htm","label":"Park road status"}],"customValues":{"best_time":"morning","crowds":"packed","photo_notes":"From the overlook a 24 mm lens takes in the whole spring. On the boardwalk, shoot the runoff channels instead of the steam."},"customNotes":{"crowds":"Quieter before 9:00 and after 18:00"},"sources":[{"url":"https://www.nps.gov/places/000/grand-prismatic-spring.htm","kind":"page","capturedOn":"2026-09-20","supports":["arrival","restrictions"]}],"factsCheckedOn":"2026-09-20","reviewBy":"2027-04-01","reviewNotes":"The overlook pin comes from your GPX of 18 September; please confirm it. The trail distance is from the NPS page (0.6 mi each way)."}},"create_a_spot_before_the_creator_has_sent_its_pin":{"summary":"Create a spot before the creator has sent its pin","value":{"title":"Lamar Valley","kicker":"Yellowstone, northeast entrance road","reviewNotes":"No pin yet: the creator is sending the pullout they use for the bison herds."}}}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpotWrite"},"examples":{"create_a_complete_spot_in_one_call":{"summary":"Create a complete spot in one call","value":{"spotId":"k1709e2vj4sk8q6x0d3m5r7t9w1y3b5c","spotKey":"01M2Z1G0Y0QG7M2V6N9R3T5W8Y","productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","title":"Grand Prismatic Spring","kicker":"Yellowstone, Midway Geyser Basin","lat":44.5251,"lon":-110.8382,"mapsUrl":"https://maps.apple.com/?ll=44.5251,-110.8382&q=Grand%20Prismatic%20Spring","shortDescription":"The largest hot spring in the United States. See it from the boardwalk, then from the overlook above the Fairy Falls trail.","longDescription":"Grand Prismatic is about 110 meters across, and from the boardwalk you mostly see steam and the orange mats that run off toward the Firehole River. For the colors, park at the Fairy Falls trailhead and follow the trail to the signed spur for the overlook: about 1 km each way, 20 minutes up. The whole spring opens up below the platform. Come on a warm, dry morning; on a cold day the steam hides everything.","color":null,"cardOrientation":"landscape","customValues":{"best_time":"morning","crowds":"packed","photo_notes":"From the overlook a 24 mm lens takes in the whole spring. On the boardwalk, shoot the runoff channels instead of the steam."},"tripFacts":{"elevationM":2176,"elevationRefersTo":"ground","busyness":5,"bestSeason":"Late May to September"},"arrival":{"byCar":{"directions":"Grand Loop Road, 11 km north of Old Faithful. Midway Geyser Basin lot.","parking":"Midway Geyser Basin lot, full by 10:00 in summer. Fairy Falls trailhead lot 1.6 km south.","walkToSpotMin":10},"byTrainBus":{"none":true},"bestTime":"Mid morning on a warm, dry day: cold air turns the steam into fog that hides the colors."},"mapLinks":[],"imagesEnabled":true,"customPropsEnabled":true,"archived":false,"ref":null,"accessMode":"short_walk","pinLabel":null,"pins":[{"kind":"viewpoint","label":"Grand Prismatic Overlook","lat":44.5192,"lon":-110.8391,"note":"Platform on a spur of the Fairy Falls trail, about 1 km from the trailhead lot."},{"kind":"parking","label":"Fairy Falls trailhead lot","lat":44.5153,"lon":-110.8325,"note":"For the overlook. Full by mid morning in July and August."}],"links":[{"kind":"official","url":"https://www.nps.gov/places/000/grand-prismatic-spring.htm","label":"Grand Prismatic Spring (NPS)"},{"kind":"status","url":"https://www.nps.gov/yell/planyourvisit/conditions.htm","label":"Park road status"}],"status":null,"fees":[{"label":"Park entrance, private vehicle, 7 days","amount":35,"currency":"USD","per":"vehicle","paidWhere":"online","sourceUrl":"https://www.nps.gov/yell/planyourvisit/fees.htm","checkedOn":"2026-09-20"}],"schedule":null,"features":[],"restrictions":[{"kind":"no_drone","label":"No drones in the park","note":"Drones are banned in all US national parks."},{"kind":"no_entry","label":"Stay on the boardwalk","note":"The crust around the spring is thin, and the water under it is scalding."}],"events":[],"food":null,"areaId":null,"timeZone":"America/Denver","timeZoneManual":false,"customNotes":{"crowds":"Quieter before 9:00 and after 18:00"},"sources":[{"url":"https://www.nps.gov/places/000/grand-prismatic-spring.htm","kind":"page","capturedOn":"2026-09-20","supports":["arrival","restrictions"]}],"reviewNotes":"The overlook pin comes from your GPX of 18 September; please confirm it. The trail distance is from the NPS page (0.6 mi each way).","factsCheckedOn":"2026-09-20","reviewBy":"2027-04-01","siteChange":null,"createdAt":1789895640000,"updatedAt":1789895640000,"photos":[],"chapters":[],"routes":[]}},"create_a_spot_before_the_creator_has_sent_its_pin":{"summary":"Create a spot before the creator has sent its pin","value":{"spotId":"k17rwzt006kbqwjbs5jrqk4jjf5srec9","spotKey":"01M3GYV6A0Y3SYC62RBPEA9S0C","productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","title":"Lamar Valley","kicker":"Yellowstone, northeast entrance road","lat":null,"lon":null,"mapsUrl":null,"shortDescription":null,"longDescription":null,"color":null,"cardOrientation":"landscape","customValues":{},"tripFacts":null,"arrival":null,"mapLinks":[],"imagesEnabled":true,"customPropsEnabled":true,"archived":false,"ref":null,"accessMode":null,"pinLabel":null,"pins":[],"links":[],"status":null,"fees":[],"schedule":null,"features":[],"restrictions":[],"events":[],"food":null,"areaId":null,"timeZone":null,"timeZoneManual":false,"customNotes":{},"sources":[],"reviewNotes":"No pin yet: the creator is sending the pullout they use for the bison herds.","factsCheckedOn":null,"reviewBy":null,"siteChange":null,"createdAt":1789895640000,"updatedAt":1789895640000,"photos":[],"chapters":[],"routes":[]}}}}}},"400":{"description":"Invalid request: invalid_argument, invalid_request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}},"invalid_request":{"summary":"The input was refused","value":{"error":{"code":"invalid_request","message":"A writer refused a value: a map link on a host that is not allowed, a title that is too long, a date that does not exist, too many items in a list. The message is the writer's own sentence."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: api_scope_required, forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"api_scope_required":{"summary":"The key lacks a scope","value":{"error":{"code":"api_scope_required","message":"A read-only key called a write operation, or a key without the publish option called publish_changes."}}},"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"413":{"description":"Too large: payload_too_large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"payload_too_large":{"summary":"The request is too large","value":{"error":{"code":"payload_too_large","message":"A JSON body over 2 MB, an image over 6 MB, a batch upload over 19 MB, or an MCP message over 2 MB."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}}},"/spots/{spotId}":{"get":{"operationId":"get_spot","summary":"One spot with its photos, chapters and routes","description":"The editor view of a spot: every field plus the photos, the chapters it belongs to and the routes that reach it.","tags":["spots"],"x-scope":"read","x-stability":"stable","x-since":"2026-09-17","x-mcp-tool":"get_spot","parameters":[{"name":"spotId","in":"path","required":true,"description":"Id of the spot (spotId from list_spots).","schema":{"type":"string","x-sceniq-id":"spots"},"example":"k1709e2vj4sk8q6x0d3m5r7t9w1y3b5c"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpotDetail"},"examples":{"read_a_spot_with_its_photos_chapters_and_routes":{"summary":"Read a spot with its photos, chapters and routes","value":{"spotId":"k1709e2vj4sk8q6x0d3m5r7t9w1y3b5c","spotKey":"01M2Z1G0Y0QG7M2V6N9R3T5W8Y","productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","title":"Grand Prismatic Spring","kicker":"Yellowstone, Midway Geyser Basin","lat":44.5251,"lon":-110.8382,"mapsUrl":"https://maps.apple.com/?ll=44.5251,-110.8382&q=Grand%20Prismatic%20Spring","shortDescription":"The largest hot spring in the United States. See it from the boardwalk, then from the overlook above the Fairy Falls trail.","longDescription":"Grand Prismatic is about 110 meters across, and from the boardwalk you mostly see steam and the orange mats that run off toward the Firehole River. For the colors, park at the Fairy Falls trailhead and follow the trail to the signed spur for the overlook: about 1 km each way, 20 minutes up. The whole spring opens up below the platform. Come on a warm, dry morning; on a cold day the steam hides everything.","color":null,"cardOrientation":"landscape","customValues":{"best_time":"morning","crowds":"packed","photo_notes":"From the overlook a 24 mm lens takes in the whole spring. On the boardwalk, shoot the runoff channels instead of the steam."},"tripFacts":{"elevationM":2176,"elevationRefersTo":"ground","busyness":5,"bestSeason":"Late May to September"},"arrival":{"byCar":{"directions":"Grand Loop Road, 11 km north of Old Faithful. Midway Geyser Basin lot.","parking":"Midway Geyser Basin lot, full by 10:00 in summer. Fairy Falls trailhead lot 1.6 km south.","walkToSpotMin":10},"byTrainBus":{"none":true},"bestTime":"Mid morning on a warm, dry day: cold air turns the steam into fog that hides the colors."},"mapLinks":[],"imagesEnabled":true,"customPropsEnabled":true,"archived":false,"ref":null,"accessMode":"short_walk","pinLabel":null,"pins":[{"kind":"viewpoint","label":"Grand Prismatic Overlook","lat":44.5192,"lon":-110.8391,"note":"Platform on a spur of the Fairy Falls trail, about 1 km from the trailhead lot."},{"kind":"parking","label":"Fairy Falls trailhead lot","lat":44.5153,"lon":-110.8325,"note":"For the overlook. Full by mid morning in July and August."}],"links":[{"kind":"official","url":"https://www.nps.gov/places/000/grand-prismatic-spring.htm","label":"Grand Prismatic Spring (NPS)"},{"kind":"status","url":"https://www.nps.gov/yell/planyourvisit/conditions.htm","label":"Park road status"}],"status":null,"fees":[],"schedule":null,"features":[],"restrictions":[{"kind":"no_drone","label":"No drones in the park","note":"Drones are banned in all US national parks."},{"kind":"no_entry","label":"Stay on the boardwalk","note":"The crust around the spring is thin, and the water under it is scalding."}],"events":[],"food":null,"areaId":"area_01m3gvdap06m6mx2kp4t553d6g","timeZone":"America/Denver","timeZoneManual":false,"customNotes":{"crowds":"Quieter before 9:00 and after 18:00"},"sources":[{"url":"https://www.nps.gov/places/000/grand-prismatic-spring.htm","kind":"page","capturedOn":"2026-09-20","supports":["arrival","restrictions"]}],"reviewNotes":"The overlook pin comes from your GPX of 18 September; please confirm it. The trail distance is from the NPS page (0.6 mi each way).","factsCheckedOn":"2026-09-20","reviewBy":"2027-04-01","siteChange":null,"createdAt":1789895640000,"updatedAt":1790586840000,"photos":[{"mediaId":"kg71s3d5f7g9h1j3k5k7z9x1c3v5b7n9","url":"https://quiet-heron-512.convex.cloud/api/storage/grand-prismatic-overlook.webp","caption":"From the overlook on a clear September morning","credit":"Mara Lindgren","width":2048,"height":1365,"order":1},{"mediaId":"kg7p2p4j6v8y0t2r4e6w8q0a2s4d6f8g","url":"https://quiet-heron-512.convex.cloud/api/storage/grand-prismatic-aerial.webp","caption":"Runoff channels from the boardwalk","credit":"Mara Lindgren","width":1365,"height":2048,"order":2}],"chapters":[{"collectionId":"kn7e5r9t3y7v1j5p9p3a7s1d5f9g3h7j","name":"Yellowstone","kind":"chapter","order":1024},{"collectionId":"kn7a2s4d6f8g0h2j4k6k8z0x2c4v6b8n","name":"Top picks","kind":"collection","order":1024}],"routes":[{"routeId":"kx7f2h8j4k0k6z2x8c4v0b6n2m8q4w0e","name":"Fairy Falls trail","order":1024,"quickest":false}]}}}}}},"400":{"description":"Invalid request: invalid_argument","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}},"patch":{"operationId":"update_spot","summary":"Edit a spot (fields, arrival, facts, archive)","description":"Only the fields you send change; an empty string clears a text field, null clears an object, [] clears a list. customValues, arrival, mapLinks and every list are full replacements. archived true hides the spot from buyers but keeps it editable (the safe alternative to deleting once a guide has buyers). The response carries warnings (an http link) that did not stop the write.","tags":["spots"],"x-scope":"write","x-stability":"stable","x-since":"2026-09-17","x-mcp-tool":"update_spot","parameters":[{"name":"spotId","in":"path","required":true,"description":"Id of the spot (spotId from list_spots).","schema":{"type":"string","x-sceniq-id":"spots"},"example":"k1709e2vj4sk8q6x0d3m5r7t9w1y3b5c"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"accessMode":{"anyOf":[{"enum":["drive_up","short_walk","hike","multi_day","boat","cable_car","train","flight","tour_only","aerial_only"]},{"type":"null"}],"description":"How visitors reach the spot, shown as Accessibility: drive_up, short_walk, hike, multi_day, boat, cable_car, train, flight, tour_only, aerial_only. null clears. Without it the cell shows the easiest required route's grade, or Drive-up only when arrival.byCar describes a drive."},"archived":{"type":"boolean","description":"true hides the spot from every buyer surface."},"areaId":{"type":"string","description":"The area (park, island, region) the spot sits in, from set_area; its rules, fees and links show on the spot. Empty string clears."},"arrival":{"anyOf":[{"$ref":"#/components/schemas/Arrival"},{"type":"null"}],"description":"How to get there, full replacement, null clears: { byCar?: { directions, parking, walkToSpotMin, walkRoundTrip? (the minutes are there and back), none? (no car access), note? }, byTrainBus?: { route, walkFromStopMin, walkRoundTrip?, none? (no public transport, which reads differently from an empty field), note? }, byBoat?, byAir?: { airports? (IATA or ICAO codes), route?, minutes?, operatorUrl?, luggageKg?, none?, note? }, onFoot?: { route?, minutes?, roundTrip?, none?, note? }, byBike?: { same }, bestTime?, operating?, approaches?: [{ label (Argentine side), country? (AR), legs?: [{ mode: car|bus|train|tram|metro|cable_car|funicular|boat|ferry|plane|helicopter|shuttle|jeep|walk|bike|taxi|other, from?, to?, minutes?, roundTrip?, price?, payment?, note? }], hours?, entry?, note?, lat?, lon? }] (at most 6, for spots with several ways in or chains of legs), rules?: [{ text, kind?: reservation|permit|guide|registration|no_independent_travel|vehicle|other, months? [1-12] (shown only then), appliesTo?: car|all, bookingOpens?, sourceUrl? }] }."},"cardOrientation":{"enum":["portrait","landscape"],"description":"portrait or landscape (photo framing in the viewer); a spot without one reads as landscape."},"color":{"type":"string","description":"Optional pin color hex, e.g. #0071e3. Empty string clears."},"customNotes":{"type":"object","additionalProperties":{"type":"string"},"description":"One short note per custom property value, keyed by property key, shown next to the value (walls 40 EUR, morning from viewpoint 7). Full replacement ({} clears)."},"customPropsEnabled":{"type":"boolean","description":"false hides custom properties from buyers; values stay stored."},"customValues":{"type":"object","additionalProperties":{},"description":"Object keyed by property key (list_properties): text for shortLabel and longSection, a number for number, epoch ms for date, one option id for singleSelect, an array of option ids for checkbox (ids, never labels). Every required property needs a value; keys without a live property are kept unchecked. Sent for an existing spot it replaces the stored object; null for a key clears that value."},"events":{"type":"array","items":{"$ref":"#/components/schemas/SpotEvent"},"description":"Recurring or one-off events worth timing a visit for, full replacement, at most 12: [{ name, when (in words: every night at 19:45 and 20:45), dates? [YYYY-MM-DD] (the apps show the next one), months?, url?, free?, note? }]."},"factsCheckedOn":{"type":"string","description":"The day the facts were last checked against their sources (YYYY-MM-DD). Empty string clears."},"features":{"type":"array","items":{"$ref":"#/components/schemas/SpotFeature"},"description":"Parts of the site with their own rules (a monastery's closing day, a ticketed skyway), full replacement, at most 12: [{ name, note?, hours?, entry?, season?, fees? (as fees), status? (as status), url? }]."},"fees":{"type":"array","items":{"$ref":"#/components/schemas/Fee"},"description":"Fees and tickets, full replacement ([] clears), at most 30: [{ label, amount? (major units, e.g. 40 or 12.5; needs currency), currency? (EUR), free?, seeOfficial? (a price left to the official page on purpose), per?: person|vehicle|night|group|entry|day|hour, audience?: all|adult|child|foreign|domestic|resident|student|senior, paidWhere?: online|on_site|in_tour, payment?: cash_only|card_only|cash_or_card, note?, validFrom?, validUntil?, sourceUrl?, checkedOn? }]. Buyers see the amount with an as-of date; readiness flags rows past validUntil or unchecked for a year."},"food":{"anyOf":[{"$ref":"#/components/schemas/FoodNote"},{"type":"null"}],"description":"Why the spot lists no food places, null clears: { status: included (meals come with the lodge or boat) | none_nearby | bring_your_own, note? }."},"imagesEnabled":{"type":"boolean","description":"false hides the photo section from buyers; photos stay stored."},"kicker":{"type":"string","description":"Short eyebrow above the title, e.g. Patagonia, Bernese Oberland or Glacier lake. Empty string clears."},"lat":{"type":"number","description":"Latitude in decimal degrees (-90 to 90). From the creator's material or a cited source."},"links":{"type":"array","items":{"$ref":"#/components/schemas/GuideLink"},"description":"Links with a purpose, full replacement ([] clears), at most 12: [{ kind: official|website|tickets|booking|status|timetable|tide|listing|social|authority|app|other, label?, url? (http or https; http is accepted with a warning), value? (a channel that is not a URL, e.g. WeChat mini program: Li River boats), note? }]. Each needs a url or a value."},"lon":{"type":"number","description":"Longitude in decimal degrees (-180 to 180)."},"longDescription":{"type":"string","description":"The full write-up in the creator's voice. Empty string clears."},"mapLinks":{"type":"array","items":{"$ref":"#/components/schemas/MapLink"},"description":"Extra map links [{ label, url }] (https or an allowlisted map link), drawn as map pills. [] clears. For official, ticket or status pages use links instead."},"mapsUrl":{"type":"string","description":"The creator's own map link: https on Google Maps, Apple Maps, Swisstopo, OpenStreetMap or SchweizMobil, or a geo: URI. Empty string clears."},"pinLabel":{"type":"string","description":"What the main pin marks for a spot that is an area or a line, shown as Pinned: <label> (Ti Top viewpoint). Empty string clears."},"pins":{"type":"array","items":{"$ref":"#/components/schemas/SpotPin"},"description":"Extra points, full replacement ([] clears), at most 12: [{ kind: viewpoint|entrance|gate|trailhead|parking|stop|pier|summit|other, label, lat, lon, months? [1-12] (only reachable then), note? }]. Each gets its own map links and a place on the web map."},"ref":{"type":"string","description":"Your own stable key for this spot (af04-abu-simbel), unique in the guide; upsert_spots matches on it. Empty string clears."},"restrictions":{"type":"array","items":{"$ref":"#/components/schemas/Restriction"},"description":"Rules on site, full replacement, at most 20: [{ kind: no_photo|wide_only|no_drone|no_entry|no_stopping|no_parking|other, label, note?, lat?, lon?, radiusM?, line? ([[lon, lat], ...] for a stretch of road), sourceUrl? }]."},"reviewBy":{"type":"string","description":"The day the facts need a new check (YYYY-MM-DD), e.g. when a season, fare or timetable runs out. get_guide_readiness and get_publish_status warn once it has passed. Empty string clears."},"reviewNotes":{"type":"string","description":"Notes for the creator's review (why a value was chosen, what could not be verified). Never shown to buyers; get_guide_readiness lists them. Empty string clears."},"schedule":{"anyOf":[{"$ref":"#/components/schemas/Schedule"},{"type":"null"}],"description":"Structured opening hours, null clears; the free-text hours stay the fallback: { hours?: [{ from? (MM-DD), to? (MM-DD, may wrap over the new year), weekdays? [1-7], closed?, open? (HH:MM or sunrise|sunset), close? (HH:MM or sunrise|sunset), openOffsetMin?, closeOffsetMin? (minutes around a sun anchor, -60 = an hour before), lastEntry? (HH:MM), leaveBy? (HH:MM), note? }], specialDays?: [{ date? or rule? (first Sunday of the month), closed?, open?, close?, note? }], slots?: { first, last, everyMin, cap?, note? }, validFrom?, validUntil?, sourceUrl?, checkedOn?, note? }. The last matching band wins, so list the year-round band first and exceptions after it. The apps show today's hours in the spot's time zone."},"shortDescription":{"type":"string","description":"One or two sentences for the card. Empty string clears."},"siteChange":{"anyOf":[{"$ref":"#/components/schemas/SiteChange"},{"type":"null"}],"description":"The day something at the spot changed (a bridge replaced, boats banned), null clears: { on (YYYY-MM-DD), note? }. Readiness flags photos captured before it."},"sources":{"type":"array","items":{"$ref":"#/components/schemas/SourceRef"},"description":"Research evidence for reviewers, never shown to buyers; full replacement, at most 40: [{ url? or title?, kind?: page|api|archive|document|other, capturedOn?, note?, supports? (which facts it backs, e.g. fees, arrival.operating, lat/lon), conflict? (true when it disagrees with another source on those facts) }]."},"status":{"anyOf":[{"$ref":"#/components/schemas/StatusNotice"},{"type":"null"}],"description":"Closure or works notice, null clears: { state: open|partly_closed|closed|reopening, note?, since?, until? (the day the state is expected to end; buyers stop seeing the notice after it), sourceUrl?, checkedOn? }. reopening with until means reopens on that day."},"timeZone":{"type":"string","description":"IANA zone (America/Phoenix). Derived from the pin on every write; set it only when the lookup is wrong near a border. Empty string hands it back to the pin."},"title":{"type":"string","description":"Place name as locals know it, e.g. Oeschinensee or Fushimi Inari-taisha. Cannot be empty."},"tripFacts":{"anyOf":[{"$ref":"#/components/schemas/TripFacts"},{"type":"null"}],"description":"The planning stats bar, null clears: { elevationM? (meters; 0 is a stated sea level, absent is unknown), elevationRefersTo?: viewpoint|summit|ground|water|trailhead, elevationSource?, busyness? (1 quiet to 5 packed, shown as Crowdedness), bestSeason? }."}},"additionalProperties":false},"examples":{"point_a_spot_at_its_park_area_and_drop_the_fee_the_area_now_carries":{"summary":"Point a spot at its park area and drop the fee the area now carries","value":{"areaId":"area_01m3gvdap06m6mx2kp4t553d6g","fees":[]}},"record_a_partial_closure_and_move_the_review_date":{"summary":"Record a partial closure and move the review date","value":{"status":{"state":"partly_closed","note":"The south end of the boardwalk is closed for repairs. The overlook trail is open.","since":"2026-09-22","until":"2026-10-31","sourceUrl":"https://www.nps.gov/yell/planyourvisit/conditions.htm","checkedOn":"2026-09-28"},"reviewBy":"2026-11-01"}},"archive_a_spot_buyers_stop_seeing_it_the_row_stays_editable":{"summary":"Archive a spot: buyers stop seeing it, the row stays editable","value":{"archived":true}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpotWrite"},"examples":{"point_a_spot_at_its_park_area_and_drop_the_fee_the_area_now_carries":{"summary":"Point a spot at its park area and drop the fee the area now carries","value":{"spotId":"k1709e2vj4sk8q6x0d3m5r7t9w1y3b5c","spotKey":"01M2Z1G0Y0QG7M2V6N9R3T5W8Y","productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","title":"Grand Prismatic Spring","kicker":"Yellowstone, Midway Geyser Basin","lat":44.5251,"lon":-110.8382,"mapsUrl":"https://maps.apple.com/?ll=44.5251,-110.8382&q=Grand%20Prismatic%20Spring","shortDescription":"The largest hot spring in the United States. See it from the boardwalk, then from the overlook above the Fairy Falls trail.","longDescription":"Grand Prismatic is about 110 meters across, and from the boardwalk you mostly see steam and the orange mats that run off toward the Firehole River. For the colors, park at the Fairy Falls trailhead and follow the trail to the signed spur for the overlook: about 1 km each way, 20 minutes up. The whole spring opens up below the platform. Come on a warm, dry morning; on a cold day the steam hides everything.","color":null,"cardOrientation":"landscape","customValues":{"best_time":"morning","crowds":"packed","photo_notes":"From the overlook a 24 mm lens takes in the whole spring. On the boardwalk, shoot the runoff channels instead of the steam."},"tripFacts":{"elevationM":2176,"elevationRefersTo":"ground","busyness":5,"bestSeason":"Late May to September"},"arrival":{"byCar":{"directions":"Grand Loop Road, 11 km north of Old Faithful. Midway Geyser Basin lot.","parking":"Midway Geyser Basin lot, full by 10:00 in summer. Fairy Falls trailhead lot 1.6 km south.","walkToSpotMin":10},"byTrainBus":{"none":true},"bestTime":"Mid morning on a warm, dry day: cold air turns the steam into fog that hides the colors."},"mapLinks":[],"imagesEnabled":true,"customPropsEnabled":true,"archived":false,"ref":null,"accessMode":"short_walk","pinLabel":null,"pins":[{"kind":"viewpoint","label":"Grand Prismatic Overlook","lat":44.5192,"lon":-110.8391,"note":"Platform on a spur of the Fairy Falls trail, about 1 km from the trailhead lot."},{"kind":"parking","label":"Fairy Falls trailhead lot","lat":44.5153,"lon":-110.8325,"note":"For the overlook. Full by mid morning in July and August."}],"links":[{"kind":"official","url":"https://www.nps.gov/places/000/grand-prismatic-spring.htm","label":"Grand Prismatic Spring (NPS)"},{"kind":"status","url":"https://www.nps.gov/yell/planyourvisit/conditions.htm","label":"Park road status"}],"status":null,"fees":[],"schedule":null,"features":[],"restrictions":[{"kind":"no_drone","label":"No drones in the park","note":"Drones are banned in all US national parks."},{"kind":"no_entry","label":"Stay on the boardwalk","note":"The crust around the spring is thin, and the water under it is scalding."}],"events":[],"food":null,"areaId":"area_01m3gvdap06m6mx2kp4t553d6g","timeZone":"America/Denver","timeZoneManual":false,"customNotes":{"crowds":"Quieter before 9:00 and after 18:00"},"sources":[{"url":"https://www.nps.gov/places/000/grand-prismatic-spring.htm","kind":"page","capturedOn":"2026-09-20","supports":["arrival","restrictions"]}],"reviewNotes":"The overlook pin comes from your GPX of 18 September; please confirm it. The trail distance is from the NPS page (0.6 mi each way).","factsCheckedOn":"2026-09-20","reviewBy":"2027-04-01","siteChange":null,"createdAt":1789895640000,"updatedAt":1790586840000,"photos":[{"mediaId":"kg71s3d5f7g9h1j3k5k7z9x1c3v5b7n9","url":"https://quiet-heron-512.convex.cloud/api/storage/grand-prismatic-overlook.webp","caption":"From the overlook on a clear September morning","credit":"Mara Lindgren","width":2048,"height":1365,"order":1},{"mediaId":"kg7p2p4j6v8y0t2r4e6w8q0a2s4d6f8g","url":"https://quiet-heron-512.convex.cloud/api/storage/grand-prismatic-aerial.webp","caption":"Runoff channels from the boardwalk","credit":"Mara Lindgren","width":1365,"height":2048,"order":2}],"chapters":[{"collectionId":"kn7e5r9t3y7v1j5p9p3a7s1d5f9g3h7j","name":"Yellowstone","kind":"chapter","order":1024},{"collectionId":"kn7a2s4d6f8g0h2j4k6k8z0x2c4v6b8n","name":"Top picks","kind":"collection","order":1024}],"routes":[{"routeId":"kx7f2h8j4k0k6z2x8c4v0b6n2m8q4w0e","name":"Fairy Falls trail","order":1024,"quickest":false}]}},"record_a_partial_closure_and_move_the_review_date":{"summary":"Record a partial closure and move the review date","value":{"spotId":"k1709e2vj4sk8q6x0d3m5r7t9w1y3b5c","spotKey":"01M2Z1G0Y0QG7M2V6N9R3T5W8Y","productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","title":"Grand Prismatic Spring","kicker":"Yellowstone, Midway Geyser Basin","lat":44.5251,"lon":-110.8382,"mapsUrl":"https://maps.apple.com/?ll=44.5251,-110.8382&q=Grand%20Prismatic%20Spring","shortDescription":"The largest hot spring in the United States. See it from the boardwalk, then from the overlook above the Fairy Falls trail.","longDescription":"Grand Prismatic is about 110 meters across, and from the boardwalk you mostly see steam and the orange mats that run off toward the Firehole River. For the colors, park at the Fairy Falls trailhead and follow the trail to the signed spur for the overlook: about 1 km each way, 20 minutes up. The whole spring opens up below the platform. Come on a warm, dry morning; on a cold day the steam hides everything.","color":null,"cardOrientation":"landscape","customValues":{"best_time":"morning","crowds":"packed","photo_notes":"From the overlook a 24 mm lens takes in the whole spring. On the boardwalk, shoot the runoff channels instead of the steam."},"tripFacts":{"elevationM":2176,"elevationRefersTo":"ground","busyness":5,"bestSeason":"Late May to September"},"arrival":{"byCar":{"directions":"Grand Loop Road, 11 km north of Old Faithful. Midway Geyser Basin lot.","parking":"Midway Geyser Basin lot, full by 10:00 in summer. Fairy Falls trailhead lot 1.6 km south.","walkToSpotMin":10},"byTrainBus":{"none":true},"bestTime":"Mid morning on a warm, dry day: cold air turns the steam into fog that hides the colors."},"mapLinks":[],"imagesEnabled":true,"customPropsEnabled":true,"archived":false,"ref":null,"accessMode":"short_walk","pinLabel":null,"pins":[{"kind":"viewpoint","label":"Grand Prismatic Overlook","lat":44.5192,"lon":-110.8391,"note":"Platform on a spur of the Fairy Falls trail, about 1 km from the trailhead lot."},{"kind":"parking","label":"Fairy Falls trailhead lot","lat":44.5153,"lon":-110.8325,"note":"For the overlook. Full by mid morning in July and August."}],"links":[{"kind":"official","url":"https://www.nps.gov/places/000/grand-prismatic-spring.htm","label":"Grand Prismatic Spring (NPS)"},{"kind":"status","url":"https://www.nps.gov/yell/planyourvisit/conditions.htm","label":"Park road status"}],"status":{"state":"partly_closed","note":"The south end of the boardwalk is closed for repairs. The overlook trail is open.","since":"2026-09-22","until":"2026-10-31","sourceUrl":"https://www.nps.gov/yell/planyourvisit/conditions.htm","checkedOn":"2026-09-28"},"fees":[],"schedule":null,"features":[],"restrictions":[{"kind":"no_drone","label":"No drones in the park","note":"Drones are banned in all US national parks."},{"kind":"no_entry","label":"Stay on the boardwalk","note":"The crust around the spring is thin, and the water under it is scalding."}],"events":[],"food":null,"areaId":"area_01m3gvdap06m6mx2kp4t553d6g","timeZone":"America/Denver","timeZoneManual":false,"customNotes":{"crowds":"Quieter before 9:00 and after 18:00"},"sources":[{"url":"https://www.nps.gov/places/000/grand-prismatic-spring.htm","kind":"page","capturedOn":"2026-09-20","supports":["arrival","restrictions"]}],"reviewNotes":"The overlook pin comes from your GPX of 18 September; please confirm it. The trail distance is from the NPS page (0.6 mi each way).","factsCheckedOn":"2026-09-20","reviewBy":"2026-11-01","siteChange":null,"createdAt":1789895640000,"updatedAt":1790673240000,"photos":[{"mediaId":"kg71s3d5f7g9h1j3k5k7z9x1c3v5b7n9","url":"https://quiet-heron-512.convex.cloud/api/storage/grand-prismatic-overlook.webp","caption":"From the overlook on a clear September morning","credit":"Mara Lindgren","width":2048,"height":1365,"order":1},{"mediaId":"kg7p2p4j6v8y0t2r4e6w8q0a2s4d6f8g","url":"https://quiet-heron-512.convex.cloud/api/storage/grand-prismatic-aerial.webp","caption":"Runoff channels from the boardwalk","credit":"Mara Lindgren","width":1365,"height":2048,"order":2}],"chapters":[{"collectionId":"kn7e5r9t3y7v1j5p9p3a7s1d5f9g3h7j","name":"Yellowstone","kind":"chapter","order":1024},{"collectionId":"kn7a2s4d6f8g0h2j4k6k8z0x2c4v6b8n","name":"Top picks","kind":"collection","order":1024}],"routes":[{"routeId":"kx7f2h8j4k0k6z2x8c4v0b6n2m8q4w0e","name":"Fairy Falls trail","order":1024,"quickest":false}]}},"archive_a_spot_buyers_stop_seeing_it_the_row_stays_editable":{"summary":"Archive a spot: buyers stop seeing it, the row stays editable","value":{"spotId":"k17vh3tkknxgj40t58pmghjy9hsxcw2r","spotKey":"01M3H2AYFG8169CVH0JCQY2BN2","productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","title":"Mirror Lake","kicker":"Yosemite Valley","lat":37.7449,"lon":-119.5506,"mapsUrl":null,"shortDescription":"Half Dome reflected in a shallow pool of Tenaya Creek. It holds water in spring and early summer, and is often dry by August.","longDescription":null,"color":null,"cardOrientation":"landscape","customValues":{},"tripFacts":null,"arrival":null,"mapLinks":[],"imagesEnabled":true,"customPropsEnabled":true,"archived":true,"ref":null,"accessMode":"short_walk","pinLabel":null,"pins":[],"links":[],"status":null,"fees":[],"schedule":null,"features":[],"restrictions":[],"events":[],"food":null,"areaId":"area_01m3gvgcb04pf38p66vz544w1b","timeZone":"America/Los_Angeles","timeZoneManual":false,"customNotes":{},"sources":[],"reviewNotes":null,"factsCheckedOn":null,"reviewBy":null,"siteChange":null,"createdAt":1789895640000,"updatedAt":1790673240000,"photos":[],"chapters":[{"collectionId":"kn73r7x6mp88mxa9swcbshwd3e7zvr39","name":"Yosemite","kind":"chapter","order":5120}],"routes":[]}}}}}},"400":{"description":"Invalid request: invalid_argument, invalid_request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}},"invalid_request":{"summary":"The input was refused","value":{"error":{"code":"invalid_request","message":"A writer refused a value: a map link on a host that is not allowed, a title that is too long, a date that does not exist, too many items in a list. The message is the writer's own sentence."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: api_scope_required, forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"api_scope_required":{"summary":"The key lacks a scope","value":{"error":{"code":"api_scope_required","message":"A read-only key called a write operation, or a key without the publish option called publish_changes."}}},"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"413":{"description":"Too large: payload_too_large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"payload_too_large":{"summary":"The request is too large","value":{"error":{"code":"payload_too_large","message":"A JSON body over 2 MB, an image over 6 MB, a batch upload over 19 MB, or an MCP message over 2 MB."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}},"delete":{"operationId":"delete_spot","summary":"Delete a spot (refused once the guide has buyers)","description":"Hard delete with cascade of chapter and route links and facets. Refused with guide_sold when anyone bought the guide; archive the spot instead (update_spot archived true). Confirm with the creator before deleting.","tags":["spots"],"x-scope":"write","x-stability":"stable","x-since":"2026-09-17","x-mcp-tool":"delete_spot","parameters":[{"name":"spotId","in":"path","required":true,"description":"Id of the spot (spotId from list_spots).","schema":{"type":"string","x-sceniq-id":"spots"},"example":"k17a6gt9x95xax4n746z5c0f3h7kjpwx"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"const":true,"description":"Always true: the write went through."},"spotId":{"type":"string","x-sceniq-id":"spots","description":"The spot's id."},"deleted":{"const":true,"description":"Always true: the row is gone."}},"required":["ok","spotId","deleted"],"additionalProperties":false},"examples":{"delete_a_spot_from_a_draft_guide":{"summary":"Delete a spot from a draft guide","value":{"ok":true,"spotId":"k17a6gt9x95xax4n746z5c0f3h7kjpwx","deleted":true}}}}}},"400":{"description":"Invalid request: invalid_argument, invalid_request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}},"invalid_request":{"summary":"The input was refused","value":{"error":{"code":"invalid_request","message":"A writer refused a value: a map link on a host that is not allowed, a title that is too long, a date that does not exist, too many items in a list. The message is the writer's own sentence."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: api_scope_required, forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"api_scope_required":{"summary":"The key lacks a scope","value":{"error":{"code":"api_scope_required","message":"A read-only key called a write operation, or a key without the publish option called publish_changes."}}},"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"409":{"description":"The row's state refuses it: guide_sold","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"guide_sold":{"summary":"The guide has buyers","value":{"error":{"code":"guide_sold","message":"delete_spot on a guide someone bought. Buyers keep what they paid for."}}}}}}},"413":{"description":"Too large: payload_too_large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"payload_too_large":{"summary":"The request is too large","value":{"error":{"code":"payload_too_large","message":"A JSON body over 2 MB, an image over 6 MB, a batch upload over 19 MB, or an MCP message over 2 MB."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}}},"/guides/{productId}/spots/batch":{"post":{"operationId":"upsert_spots","summary":"Create or update up to 25 spots by your own ref","description":"Bulk and idempotent: each item is a create_spot body plus a required ref (your stable key). A spot of this guide with that ref is updated with the fields you send; any other ref creates a spot. One transaction per call, so one bad item rejects the batch and nothing half-lands; the error names the ref. Returns [{ ref, spotId, spotKey, created }] and any warnings, with status 201 even when every item was an update. Re-running the same batch never duplicates spots.","tags":["spots"],"x-scope":"write","x-stability":"beta","x-since":"2026-09-30","x-mcp-tool":"upsert_spots","parameters":[{"name":"productId","in":"path","required":true,"description":"Id of the guide (a product of type map). From list_guides or create_guide.","schema":{"type":"string","x-sceniq-id":"products"},"example":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"spots":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string","description":"Place name as locals know it, e.g. Oeschinensee or Fushimi Inari-taisha. Cannot be empty."},"kicker":{"type":"string","description":"Short eyebrow above the title, e.g. Patagonia, Bernese Oberland or Glacier lake. Empty string clears."},"lat":{"type":"number","description":"Latitude in decimal degrees (-90 to 90). From the creator's material or a cited source."},"lon":{"type":"number","description":"Longitude in decimal degrees (-180 to 180)."},"mapsUrl":{"type":"string","description":"The creator's own map link: https on Google Maps, Apple Maps, Swisstopo, OpenStreetMap or SchweizMobil, or a geo: URI. Empty string clears."},"shortDescription":{"type":"string","description":"One or two sentences for the card. Empty string clears."},"longDescription":{"type":"string","description":"The full write-up in the creator's voice. Empty string clears."},"color":{"type":"string","description":"Optional pin color hex, e.g. #0071e3. Empty string clears."},"cardOrientation":{"enum":["portrait","landscape"],"description":"portrait or landscape (photo framing in the viewer); a spot without one reads as landscape."},"customValues":{"type":"object","additionalProperties":{},"description":"Object keyed by property key (list_properties): text for shortLabel and longSection, a number for number, epoch ms for date, one option id for singleSelect, an array of option ids for checkbox (ids, never labels). Every required property needs a value; keys without a live property are kept unchecked. Sent for an existing spot it replaces the stored object; null for a key clears that value."},"arrival":{"anyOf":[{"$ref":"#/components/schemas/Arrival"},{"type":"null"}],"description":"How to get there, full replacement, null clears: { byCar?: { directions, parking, walkToSpotMin, walkRoundTrip? (the minutes are there and back), none? (no car access), note? }, byTrainBus?: { route, walkFromStopMin, walkRoundTrip?, none? (no public transport, which reads differently from an empty field), note? }, byBoat?, byAir?: { airports? (IATA or ICAO codes), route?, minutes?, operatorUrl?, luggageKg?, none?, note? }, onFoot?: { route?, minutes?, roundTrip?, none?, note? }, byBike?: { same }, bestTime?, operating?, approaches?: [{ label (Argentine side), country? (AR), legs?: [{ mode: car|bus|train|tram|metro|cable_car|funicular|boat|ferry|plane|helicopter|shuttle|jeep|walk|bike|taxi|other, from?, to?, minutes?, roundTrip?, price?, payment?, note? }], hours?, entry?, note?, lat?, lon? }] (at most 6, for spots with several ways in or chains of legs), rules?: [{ text, kind?: reservation|permit|guide|registration|no_independent_travel|vehicle|other, months? [1-12] (shown only then), appliesTo?: car|all, bookingOpens?, sourceUrl? }] }."},"mapLinks":{"type":"array","items":{"$ref":"#/components/schemas/MapLink"},"description":"Extra map links [{ label, url }] (https or an allowlisted map link), drawn as map pills. [] clears. For official, ticket or status pages use links instead."},"imagesEnabled":{"type":"boolean","description":"false hides the photo section from buyers; photos stay stored."},"customPropsEnabled":{"type":"boolean","description":"false hides custom properties from buyers; values stay stored."},"tripFacts":{"anyOf":[{"$ref":"#/components/schemas/TripFacts"},{"type":"null"}],"description":"The planning stats bar, null clears: { elevationM? (meters; 0 is a stated sea level, absent is unknown), elevationRefersTo?: viewpoint|summit|ground|water|trailhead, elevationSource?, busyness? (1 quiet to 5 packed, shown as Crowdedness), bestSeason? }."},"accessMode":{"anyOf":[{"enum":["drive_up","short_walk","hike","multi_day","boat","cable_car","train","flight","tour_only","aerial_only"]},{"type":"null"}],"description":"How visitors reach the spot, shown as Accessibility: drive_up, short_walk, hike, multi_day, boat, cable_car, train, flight, tour_only, aerial_only. null clears. Without it the cell shows the easiest required route's grade, or Drive-up only when arrival.byCar describes a drive."},"pinLabel":{"type":"string","description":"What the main pin marks for a spot that is an area or a line, shown as Pinned: <label> (Ti Top viewpoint). Empty string clears."},"pins":{"type":"array","items":{"$ref":"#/components/schemas/SpotPin"},"description":"Extra points, full replacement ([] clears), at most 12: [{ kind: viewpoint|entrance|gate|trailhead|parking|stop|pier|summit|other, label, lat, lon, months? [1-12] (only reachable then), note? }]. Each gets its own map links and a place on the web map."},"links":{"type":"array","items":{"$ref":"#/components/schemas/GuideLink"},"description":"Links with a purpose, full replacement ([] clears), at most 12: [{ kind: official|website|tickets|booking|status|timetable|tide|listing|social|authority|app|other, label?, url? (http or https; http is accepted with a warning), value? (a channel that is not a URL, e.g. WeChat mini program: Li River boats), note? }]. Each needs a url or a value."},"status":{"anyOf":[{"$ref":"#/components/schemas/StatusNotice"},{"type":"null"}],"description":"Closure or works notice, null clears: { state: open|partly_closed|closed|reopening, note?, since?, until? (the day the state is expected to end; buyers stop seeing the notice after it), sourceUrl?, checkedOn? }. reopening with until means reopens on that day."},"fees":{"type":"array","items":{"$ref":"#/components/schemas/Fee"},"description":"Fees and tickets, full replacement ([] clears), at most 30: [{ label, amount? (major units, e.g. 40 or 12.5; needs currency), currency? (EUR), free?, seeOfficial? (a price left to the official page on purpose), per?: person|vehicle|night|group|entry|day|hour, audience?: all|adult|child|foreign|domestic|resident|student|senior, paidWhere?: online|on_site|in_tour, payment?: cash_only|card_only|cash_or_card, note?, validFrom?, validUntil?, sourceUrl?, checkedOn? }]. Buyers see the amount with an as-of date; readiness flags rows past validUntil or unchecked for a year."},"schedule":{"anyOf":[{"$ref":"#/components/schemas/Schedule"},{"type":"null"}],"description":"Structured opening hours, null clears; the free-text hours stay the fallback: { hours?: [{ from? (MM-DD), to? (MM-DD, may wrap over the new year), weekdays? [1-7], closed?, open? (HH:MM or sunrise|sunset), close? (HH:MM or sunrise|sunset), openOffsetMin?, closeOffsetMin? (minutes around a sun anchor, -60 = an hour before), lastEntry? (HH:MM), leaveBy? (HH:MM), note? }], specialDays?: [{ date? or rule? (first Sunday of the month), closed?, open?, close?, note? }], slots?: { first, last, everyMin, cap?, note? }, validFrom?, validUntil?, sourceUrl?, checkedOn?, note? }. The last matching band wins, so list the year-round band first and exceptions after it. The apps show today's hours in the spot's time zone."},"features":{"type":"array","items":{"$ref":"#/components/schemas/SpotFeature"},"description":"Parts of the site with their own rules (a monastery's closing day, a ticketed skyway), full replacement, at most 12: [{ name, note?, hours?, entry?, season?, fees? (as fees), status? (as status), url? }]."},"restrictions":{"type":"array","items":{"$ref":"#/components/schemas/Restriction"},"description":"Rules on site, full replacement, at most 20: [{ kind: no_photo|wide_only|no_drone|no_entry|no_stopping|no_parking|other, label, note?, lat?, lon?, radiusM?, line? ([[lon, lat], ...] for a stretch of road), sourceUrl? }]."},"events":{"type":"array","items":{"$ref":"#/components/schemas/SpotEvent"},"description":"Recurring or one-off events worth timing a visit for, full replacement, at most 12: [{ name, when (in words: every night at 19:45 and 20:45), dates? [YYYY-MM-DD] (the apps show the next one), months?, url?, free?, note? }]."},"food":{"anyOf":[{"$ref":"#/components/schemas/FoodNote"},{"type":"null"}],"description":"Why the spot lists no food places, null clears: { status: included (meals come with the lodge or boat) | none_nearby | bring_your_own, note? }."},"areaId":{"type":"string","description":"The area (park, island, region) the spot sits in, from set_area; its rules, fees and links show on the spot. Empty string clears."},"timeZone":{"type":"string","description":"IANA zone (America/Phoenix). Derived from the pin on every write; set it only when the lookup is wrong near a border. Empty string hands it back to the pin."},"customNotes":{"type":"object","additionalProperties":{"type":"string"},"description":"One short note per custom property value, keyed by property key, shown next to the value (walls 40 EUR, morning from viewpoint 7). Full replacement ({} clears)."},"sources":{"type":"array","items":{"$ref":"#/components/schemas/SourceRef"},"description":"Research evidence for reviewers, never shown to buyers; full replacement, at most 40: [{ url? or title?, kind?: page|api|archive|document|other, capturedOn?, note?, supports? (which facts it backs, e.g. fees, arrival.operating, lat/lon), conflict? (true when it disagrees with another source on those facts) }]."},"reviewNotes":{"type":"string","description":"Notes for the creator's review (why a value was chosen, what could not be verified). Never shown to buyers; get_guide_readiness lists them. Empty string clears."},"factsCheckedOn":{"type":"string","description":"The day the facts were last checked against their sources (YYYY-MM-DD). Empty string clears."},"reviewBy":{"type":"string","description":"The day the facts need a new check (YYYY-MM-DD), e.g. when a season, fare or timetable runs out. get_guide_readiness and get_publish_status warn once it has passed. Empty string clears."},"siteChange":{"anyOf":[{"$ref":"#/components/schemas/SiteChange"},{"type":"null"}],"description":"The day something at the spot changed (a bridge replaced, boats banned), null clears: { on (YYYY-MM-DD), note? }. Readiness flags photos captured before it."},"ref":{"type":"string","description":"Required: your own stable key for the spot, 1 to 80 characters (letters, digits, dot, underscore, colon or hyphen, a letter or digit first), once per batch. A spot of this guide with that ref is updated with the fields sent; any other ref creates a spot."}},"required":["title","ref"],"additionalProperties":false},"description":"Up to 25 items: every create_spot field plus ref (required)."}},"required":["spots"],"additionalProperties":false},"examples":{"first_run_three_spots_created_by_your_own_ref":{"summary":"First run: three spots created by your own ref","value":{"spots":[{"ref":"yose-tunnel-view","title":"Tunnel View","kicker":"Yosemite Valley","lat":37.7156,"lon":-119.677,"mapsUrl":"https://www.google.com/maps/search/?api=1&query=37.7156,-119.677","shortDescription":"El Capitan, Half Dome and Bridalveil Fall in one frame, at the east end of the Wawona Tunnel.","accessMode":"drive_up","customValues":{"best_time":"sunset","crowds":"busy"}},{"ref":"yose-glacier-point","title":"Glacier Point","kicker":"Yosemite, above the valley","lat":37.7307,"lon":-119.5741,"shortDescription":"Half Dome, Vernal Fall and Nevada Fall from nearly 1,000 meters above the valley floor.","accessMode":"drive_up","customValues":{"best_time":"sunset","crowds":"packed"}},{"ref":"yose-taft-point","title":"Taft Point","kicker":"Yosemite, Glacier Point Road","lat":37.7125,"lon":-119.6049,"shortDescription":"Fissures in the granite and a sheer drop to the valley, with El Capitan across the gap.","accessMode":"hike","customValues":{"best_time":"sunset","crowds":"busy"}}]}},"run_again_with_changes_known_refs_update_a_new_ref_creates_nothing_duplicates":{"summary":"Run again with changes: known refs update, a new ref creates, nothing duplicates","value":{"spots":[{"ref":"yose-tunnel-view","title":"Tunnel View","longDescription":"The view opened with the Wawona Tunnel in 1933: El Capitan on the left, Half Dome at the back, Bridalveil Fall on the right. The lots fill for sunset from spring to autumn; in winter, come as a storm clears.","sources":[{"url":"http://www.yosemite.ca.us/library/wawona_tunnel.html","title":"Wawona Tunnel history","kind":"document","supports":["longDescription"]}]},{"ref":"yose-glacier-point","title":"Glacier Point","arrival":{"byCar":{"directions":"Glacier Point Road from Chinquapin, 26 km to the end of the road.","parking":"Large lot at the end of the road; full by late afternoon in summer.","walkToSpotMin":5},"rules":[{"text":"Glacier Point Road is closed to cars in winter, usually from November to late May.","kind":"vehicle","months":[11,12,1,2,3,4,5],"appliesTo":"car","sourceUrl":"https://www.nps.gov/yose/planyourvisit/conditions.htm"}]}},{"ref":"yose-sentinel-dome","title":"Sentinel Dome","kicker":"Yosemite, Glacier Point Road","lat":37.7231,"lon":-119.5845,"shortDescription":"A bare granite dome with a view all the way round, from El Capitan to Half Dome.","accessMode":"hike"}]}}}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"productId":{"type":"string","x-sceniq-id":"products","description":"The guide's id."},"created":{"type":"number","description":"Spots created."},"updated":{"type":"number","description":"Spots updated."},"results":{"type":"array","items":{"type":"object","properties":{"ref":{"type":"string","description":"Your ref."},"spotId":{"type":"string","x-sceniq-id":"spots","description":"The spot's id."},"spotKey":{"type":"string","description":"The spot's key."},"created":{"type":"boolean","description":"true when this call created the spot."}},"required":["ref","spotId","spotKey","created"],"additionalProperties":false},"description":"One result per item, in order."},"warnings":{"type":"array","items":{"type":"string"},"description":"Notes about things the write accepted but you should look at (a plain http link). Present only when there are any."}},"required":["productId","created","updated","results"],"additionalProperties":false},"examples":{"first_run_three_spots_created_by_your_own_ref":{"summary":"First run: three spots created by your own ref","value":{"productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","created":3,"updated":0,"results":[{"ref":"yose-tunnel-view","spotId":"k17bc3xz8h6f4d2s0q9w7e5r3t1y2v4j","spotKey":"01M2Z1G0Y0R2K5P8S1V4X7Z0C3","created":true},{"ref":"yose-glacier-point","spotId":"k1736b344br1c7m8qk8ks4sfndxyyftj","spotKey":"01M3H2AWH0F9PB64V7QB8QS0MC","created":true},{"ref":"yose-taft-point","spotId":"k17hdgc1c8j423kgq30t9x5hyv1tv8yb","spotKey":"01M3H2AXG8GB8YNF4FCEFARFN5","created":true}]}},"run_again_with_changes_known_refs_update_a_new_ref_creates_nothing_duplicates":{"summary":"Run again with changes: known refs update, a new ref creates, nothing duplicates","value":{"productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","created":1,"updated":2,"results":[{"ref":"yose-tunnel-view","spotId":"k17bc3xz8h6f4d2s0q9w7e5r3t1y2v4j","spotKey":"01M2Z1G0Y0R2K5P8S1V4X7Z0C3","created":false},{"ref":"yose-glacier-point","spotId":"k1736b344br1c7m8qk8ks4sfndxyyftj","spotKey":"01M3H2AWH0F9PB64V7QB8QS0MC","created":false},{"ref":"yose-sentinel-dome","spotId":"k17hh93896ctjmrxq55mxp7qt176q6f6","spotKey":"01M3KMNRY0V8ZPTG4HCY75DZFB","created":true}],"warnings":["yose-tunnel-view: sources 1 url uses http, not https: http://www.yosemite.ca.us/library/wawona_tunnel.html"]}}}}}},"400":{"description":"Invalid request: invalid_argument, invalid_request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}},"invalid_request":{"summary":"The input was refused","value":{"error":{"code":"invalid_request","message":"A writer refused a value: a map link on a host that is not allowed, a title that is too long, a date that does not exist, too many items in a list. The message is the writer's own sentence."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: api_scope_required, forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"api_scope_required":{"summary":"The key lacks a scope","value":{"error":{"code":"api_scope_required","message":"A read-only key called a write operation, or a key without the publish option called publish_changes."}}},"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"413":{"description":"Too large: payload_too_large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"payload_too_large":{"summary":"The request is too large","value":{"error":{"code":"payload_too_large","message":"A JSON body over 2 MB, an image over 6 MB, a batch upload over 19 MB, or an MCP message over 2 MB."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}}},"/spots/{spotId}/routes":{"put":{"operationId":"set_spot_routes","summary":"Set which routes reach this spot","description":"Full replacement of the route ids linked to one spot; new links append at the end of each route.","tags":["spots"],"x-scope":"write","x-stability":"stable","x-since":"2026-09-17","x-mcp-tool":"set_spot_routes","parameters":[{"name":"spotId","in":"path","required":true,"description":"Id of the spot (spotId from list_spots).","schema":{"type":"string","x-sceniq-id":"spots"},"example":"k1709e2vj4sk8q6x0d3m5r7t9w1y3b5c"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"routeIds":{"type":"array","items":{"type":"string","x-sceniq-id":"routes"},"description":"All route ids that should link to this spot."}},"required":["routeIds"],"additionalProperties":false},"examples":{"link_the_routes_that_reach_a_spot":{"summary":"Link the routes that reach a spot","value":{"routeIds":["kx7f2h8j4k0k6z2x8c4v0b6n2m8q4w0e"]}},"unlink_every_route_from_a_spot":{"summary":"Unlink every route from a spot","value":{"routeIds":[]}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"const":true,"description":"Always true: the write went through."},"spotId":{"type":"string","x-sceniq-id":"spots","description":"The spot's id."},"edges":{"type":"number","description":"How many links the list now holds."}},"required":["ok","spotId","edges"],"additionalProperties":false},"examples":{"link_the_routes_that_reach_a_spot":{"summary":"Link the routes that reach a spot","value":{"ok":true,"spotId":"k1709e2vj4sk8q6x0d3m5r7t9w1y3b5c","edges":1}},"unlink_every_route_from_a_spot":{"summary":"Unlink every route from a spot","value":{"ok":true,"spotId":"k17hdgc1c8j423kgq30t9x5hyv1tv8yb","edges":0}}}}}},"400":{"description":"Invalid request: invalid_argument, invalid_request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}},"invalid_request":{"summary":"The input was refused","value":{"error":{"code":"invalid_request","message":"A writer refused a value: a map link on a host that is not allowed, a title that is too long, a date that does not exist, too many items in a list. The message is the writer's own sentence."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: api_scope_required, forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"api_scope_required":{"summary":"The key lacks a scope","value":{"error":{"code":"api_scope_required","message":"A read-only key called a write operation, or a key without the publish option called publish_changes."}}},"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"413":{"description":"Too large: payload_too_large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"payload_too_large":{"summary":"The request is too large","value":{"error":{"code":"payload_too_large","message":"A JSON body over 2 MB, an image over 6 MB, a batch upload over 19 MB, or an MCP message over 2 MB."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}}},"/guides/{productId}/areas":{"get":{"operationId":"list_areas","summary":"Parks, islands and regions shared by several spots","description":"Each area with its rules, fees, season, links and status, plus the spotKeys that point at it (update_spot areaId).","tags":["areas"],"x-scope":"read","x-stability":"beta","x-since":"2026-09-30","x-mcp-tool":"list_areas","parameters":[{"name":"productId","in":"path","required":true,"description":"Id of the guide (a product of type map). From list_guides or create_guide.","schema":{"type":"string","x-sceniq-id":"products"},"example":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"productId":{"type":"string","x-sceniq-id":"products","description":"The guide's id."},"areas":{"type":"array","items":{"$ref":"#/components/schemas/AreaWithSpots"},"description":"Every area of the guide."}},"required":["productId","areas"],"additionalProperties":false},"examples":{"list_a_guide_s_areas_and_the_spots_that_point_at_them":{"summary":"List a guide's areas and the spots that point at them","value":{"productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","areas":[{"id":"area_01m3gvdap06m6mx2kp4t553d6g","name":"Yellowstone National Park","kind":"park","note":"One entrance pass covers every spot in the Yellowstone chapter. Cell coverage is patchy between the geyser basins; download the guide before you drive in.","season":"Most park roads are open to cars from May to early November.","rules":[{"text":"Stay on boardwalks and marked trails in every thermal area.","kind":"other","sourceUrl":"https://www.nps.gov/yell/planyourvisit/safety.htm"}],"fees":[{"label":"Park entrance, private vehicle, 7 days","amount":35,"currency":"USD","per":"vehicle","paidWhere":"online","sourceUrl":"https://www.nps.gov/yell/planyourvisit/fees.htm","checkedOn":"2026-09-20"}],"links":[{"kind":"official","url":"https://www.nps.gov/yell/index.htm","label":"Yellowstone National Park (NPS)"},{"kind":"status","url":"https://www.nps.gov/yell/planyourvisit/conditions.htm","label":"Park road status"}],"sources":[{"url":"https://www.nps.gov/yell/planyourvisit/fees.htm","kind":"page","capturedOn":"2026-09-20","supports":["fees"]}],"spotKeys":["01M2Z1G0Y0QG7M2V6N9R3T5W8Y"]},{"id":"area_01m3gvgcb04pf38p66vz544w1b","name":"Yosemite National Park","kind":"park","season":"Open all year. Glacier Point Road and Tioga Road close to cars in winter.","rules":[{"text":"Glacier Point Road and Tioga Road are closed to cars in winter, usually from November to late May.","kind":"vehicle","months":[11,12,1,2,3,4,5],"appliesTo":"car","sourceUrl":"https://www.nps.gov/yose/planyourvisit/conditions.htm"}],"fees":[{"label":"Park entrance, private vehicle, 7 days","amount":35,"currency":"USD","per":"vehicle","sourceUrl":"https://www.nps.gov/yose/planyourvisit/fees.htm","checkedOn":"2026-09-20"}],"links":[{"kind":"official","url":"https://www.nps.gov/yose/index.htm","label":"Yosemite National Park (NPS)"},{"kind":"timetable","url":"https://yarts.com/","label":"YARTS buses into the valley"}],"spotKeys":["01M2Z1G0Y0R2K5P8S1V4X7Z0C3","01M3H2AWH0F9PB64V7QB8QS0MC","01M3H2AXG8GB8YNF4FCEFARFN5","01M3H2AYFG8169CVH0JCQY2BN2"]}]}}}}}},"400":{"description":"Invalid request: invalid_argument","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}},"put":{"operationId":"set_area","summary":"Create an area, or replace one area's content","description":"Rules that apply to a whole park, island or region (Yellowstone's fee and road season, Rapa Nui's entry form, Tibet's permit) live once here; spots point at it with update_spot areaId and buyers see it on each spot. Without areaId this creates an area and returns its id; with areaId every field is replaced (fields you leave out are cleared). At most 50 per guide.","tags":["areas"],"x-scope":"write","x-stability":"beta","x-since":"2026-09-30","x-mcp-tool":"set_area","parameters":[{"name":"productId","in":"path","required":true,"description":"Id of the guide (a product of type map). From list_guides or create_guide.","schema":{"type":"string","x-sceniq-id":"products"},"example":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"The area's name, at most 100 characters, e.g. Yellowstone National Park."},"areaId":{"type":"string","description":"The area to replace (from list_areas); omit to create one."},"fees":{"type":"array","items":{"$ref":"#/components/schemas/Fee"},"description":"Fees and tickets, full replacement ([] clears), at most 30: [{ label, amount? (major units, e.g. 40 or 12.5; needs currency), currency? (EUR), free?, seeOfficial? (a price left to the official page on purpose), per?: person|vehicle|night|group|entry|day|hour, audience?: all|adult|child|foreign|domestic|resident|student|senior, paidWhere?: online|on_site|in_tour, payment?: cash_only|card_only|cash_or_card, note?, validFrom?, validUntil?, sourceUrl?, checkedOn? }]. Buyers see the amount with an as-of date; readiness flags rows past validUntil or unchecked for a year."},"kind":{"enum":["park","reserve","island","region","city","other"],"description":"park, reserve, island, region, city or other."},"links":{"type":"array","items":{"$ref":"#/components/schemas/GuideLink"},"description":"Links with a purpose, full replacement ([] clears), at most 12: [{ kind: official|website|tickets|booking|status|timetable|tide|listing|social|authority|app|other, label?, url? (http or https; http is accepted with a warning), value? (a channel that is not a URL, e.g. WeChat mini program: Li River boats), note? }]. Each needs a url or a value."},"note":{"type":"string","description":"What applies across the area, in the creator's words, at most 1,000 characters."},"rules":{"type":"array","items":{"$ref":"#/components/schemas/AccessRule"},"description":"[{ text, kind?, months?, appliesTo?, bookingOpens?, sourceUrl? }], as arrival.rules."},"season":{"type":"string","description":"The area's season in words, at most 300 characters (roads open May to October)."},"sources":{"type":"array","items":{"$ref":"#/components/schemas/SourceRef"},"description":"Research evidence for reviewers, never shown to buyers; full replacement, at most 40: [{ url? or title?, kind?: page|api|archive|document|other, capturedOn?, note?, supports? (which facts it backs, e.g. fees, arrival.operating, lat/lon), conflict? (true when it disagrees with another source on those facts) }]."},"status":{"$ref":"#/components/schemas/StatusNotice","description":"Closure or works notice for the whole area: { state: open|partly_closed|closed|reopening, note?, since?, until?, sourceUrl?, checkedOn? }. set_area replaces every field, so leave it out to clear it (null is not accepted)."}},"required":["name"],"additionalProperties":false},"examples":{"create_an_area_for_a_whole_park_no_areaid":{"summary":"Create an area for a whole park (no areaId)","value":{"name":"Yellowstone National Park","kind":"park","note":"One entrance pass covers every spot in the Yellowstone chapter. Cell coverage is patchy between the geyser basins; download the guide before you drive in.","season":"Most park roads are open to cars from May to early November.","rules":[{"text":"Stay on boardwalks and marked trails in every thermal area.","kind":"other","sourceUrl":"https://www.nps.gov/yell/planyourvisit/safety.htm"}],"fees":[{"label":"Park entrance, private vehicle, 7 days","amount":35,"currency":"USD","per":"vehicle","paidWhere":"online","sourceUrl":"https://www.nps.gov/yell/planyourvisit/fees.htm","checkedOn":"2026-09-20"}],"links":[{"kind":"official","url":"https://www.nps.gov/yell/index.htm","label":"Yellowstone National Park (NPS)"},{"kind":"status","url":"https://www.nps.gov/yell/planyourvisit/conditions.htm","label":"Park road status"}],"sources":[{"url":"https://www.nps.gov/yell/planyourvisit/fees.htm","kind":"page","capturedOn":"2026-09-20","supports":["fees"]}]}},"replace_an_area_s_content_fields_left_out_are_cleared":{"summary":"Replace an area's content (fields left out are cleared)","value":{"areaId":"area_01m3gvgcb04pf38p66vz544w1b","name":"Yosemite National Park","kind":"park","season":"Open all year. Glacier Point Road and Tioga Road close to cars in winter.","rules":[{"text":"Glacier Point Road and Tioga Road are closed to cars in winter, usually from November to late May.","kind":"vehicle","months":[11,12,1,2,3,4,5],"appliesTo":"car","sourceUrl":"https://www.nps.gov/yose/planyourvisit/conditions.htm"}],"fees":[{"label":"Park entrance, private vehicle, 7 days","amount":35,"currency":"USD","per":"vehicle","sourceUrl":"https://www.nps.gov/yose/planyourvisit/fees.htm","checkedOn":"2026-09-20"}],"links":[{"kind":"official","url":"https://www.nps.gov/yose/index.htm","label":"Yosemite National Park (NPS)"},{"kind":"timetable","url":"https://yarts.com/","label":"YARTS buses into the valley"}]}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"productId":{"type":"string","x-sceniq-id":"products","description":"The guide's id."},"created":{"type":"boolean","description":"true when this call created the area."},"area":{"anyOf":[{"$ref":"#/components/schemas/AreaWithSpots"},{"type":"null"}],"description":"The area as stored."},"warnings":{"type":"array","items":{"type":"string"},"description":"Notes about things the write accepted but you should look at (a plain http link). Present only when there are any."}},"required":["productId","created","area"],"additionalProperties":false},"examples":{"create_an_area_for_a_whole_park_no_areaid":{"summary":"Create an area for a whole park (no areaId)","value":{"productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","created":true,"area":{"id":"area_01m3gvdap06m6mx2kp4t553d6g","name":"Yellowstone National Park","kind":"park","note":"One entrance pass covers every spot in the Yellowstone chapter. Cell coverage is patchy between the geyser basins; download the guide before you drive in.","season":"Most park roads are open to cars from May to early November.","rules":[{"text":"Stay on boardwalks and marked trails in every thermal area.","kind":"other","sourceUrl":"https://www.nps.gov/yell/planyourvisit/safety.htm"}],"fees":[{"label":"Park entrance, private vehicle, 7 days","amount":35,"currency":"USD","per":"vehicle","paidWhere":"online","sourceUrl":"https://www.nps.gov/yell/planyourvisit/fees.htm","checkedOn":"2026-09-20"}],"links":[{"kind":"official","url":"https://www.nps.gov/yell/index.htm","label":"Yellowstone National Park (NPS)"},{"kind":"status","url":"https://www.nps.gov/yell/planyourvisit/conditions.htm","label":"Park road status"}],"sources":[{"url":"https://www.nps.gov/yell/planyourvisit/fees.htm","kind":"page","capturedOn":"2026-09-20","supports":["fees"]}],"spotKeys":[]}}},"replace_an_area_s_content_fields_left_out_are_cleared":{"summary":"Replace an area's content (fields left out are cleared)","value":{"productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","created":false,"area":{"id":"area_01m3gvgcb04pf38p66vz544w1b","name":"Yosemite National Park","kind":"park","season":"Open all year. Glacier Point Road and Tioga Road close to cars in winter.","rules":[{"text":"Glacier Point Road and Tioga Road are closed to cars in winter, usually from November to late May.","kind":"vehicle","months":[11,12,1,2,3,4,5],"appliesTo":"car","sourceUrl":"https://www.nps.gov/yose/planyourvisit/conditions.htm"}],"fees":[{"label":"Park entrance, private vehicle, 7 days","amount":35,"currency":"USD","per":"vehicle","sourceUrl":"https://www.nps.gov/yose/planyourvisit/fees.htm","checkedOn":"2026-09-20"}],"links":[{"kind":"official","url":"https://www.nps.gov/yose/index.htm","label":"Yosemite National Park (NPS)"},{"kind":"timetable","url":"https://yarts.com/","label":"YARTS buses into the valley"}],"spotKeys":["01M2Z1G0Y0R2K5P8S1V4X7Z0C3","01M3H2AWH0F9PB64V7QB8QS0MC","01M3H2AXG8GB8YNF4FCEFARFN5","01M3H2AYFG8169CVH0JCQY2BN2"]}}}}}}},"400":{"description":"Invalid request: invalid_argument, invalid_request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}},"invalid_request":{"summary":"The input was refused","value":{"error":{"code":"invalid_request","message":"A writer refused a value: a map link on a host that is not allowed, a title that is too long, a date that does not exist, too many items in a list. The message is the writer's own sentence."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: api_scope_required, forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"api_scope_required":{"summary":"The key lacks a scope","value":{"error":{"code":"api_scope_required","message":"A read-only key called a write operation, or a key without the publish option called publish_changes."}}},"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"413":{"description":"Too large: payload_too_large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"payload_too_large":{"summary":"The request is too large","value":{"error":{"code":"payload_too_large","message":"A JSON body over 2 MB, an image over 6 MB, a batch upload over 19 MB, or an MCP message over 2 MB."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}}},"/guides/{productId}/areas/{areaId}":{"delete":{"operationId":"delete_area","summary":"Delete an area (spots lose the link, nothing else)","description":"Removes the area; spots that pointed at it keep all their own content. Confirm with the creator first.","tags":["areas"],"x-scope":"write","x-stability":"beta","x-since":"2026-09-30","x-mcp-tool":"delete_area","parameters":[{"name":"areaId","in":"path","required":true,"description":"The area's id (from list_areas).","schema":{"type":"string"},"example":"area_01m3gzdg80rp1g128z2qhqegn2"},{"name":"productId","in":"path","required":true,"description":"Id of the guide (a product of type map). From list_guides or create_guide.","schema":{"type":"string","x-sceniq-id":"products"},"example":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"const":true,"description":"Always true: the write went through."},"areaId":{"type":"string","description":"The deleted area's id."},"deleted":{"const":true,"description":"Always true: the row is gone."},"spotsUnlinked":{"type":"number","description":"Spots that pointed at the area and lost the link."}},"required":["ok","areaId","deleted","spotsUnlinked"],"additionalProperties":false},"examples":{"delete_an_area_its_spots_keep_their_own_content":{"summary":"Delete an area; its spots keep their own content","value":{"ok":true,"areaId":"area_01m3gzdg80rp1g128z2qhqegn2","deleted":true,"spotsUnlinked":1}}}}}},"400":{"description":"Invalid request: invalid_argument, invalid_request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}},"invalid_request":{"summary":"The input was refused","value":{"error":{"code":"invalid_request","message":"A writer refused a value: a map link on a host that is not allowed, a title that is too long, a date that does not exist, too many items in a list. The message is the writer's own sentence."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: api_scope_required, forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"api_scope_required":{"summary":"The key lacks a scope","value":{"error":{"code":"api_scope_required","message":"A read-only key called a write operation, or a key without the publish option called publish_changes."}}},"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"413":{"description":"Too large: payload_too_large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"payload_too_large":{"summary":"The request is too large","value":{"error":{"code":"payload_too_large","message":"A JSON body over 2 MB, an image over 6 MB, a batch upload over 19 MB, or an MCP message over 2 MB."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}}},"/guides/{productId}/chapters":{"get":{"operationId":"list_chapters","summary":"Chapters and collections with their members","description":"A chapter is a guide section (a region, a day) that can carry prose and front matter; a collection is a plain spot set (top picks). Members reference spots by spotKey, or chapters by id inside a collection.","tags":["chapters"],"x-scope":"read","x-stability":"stable","x-since":"2026-09-17","x-mcp-tool":"list_chapters","parameters":[{"name":"productId","in":"path","required":true,"description":"Id of the guide (a product of type map). From list_guides or create_guide.","schema":{"type":"string","x-sceniq-id":"products"},"example":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"productId":{"type":"string","x-sceniq-id":"products","description":"The guide's id."},"chapters":{"type":"array","items":{"$ref":"#/components/schemas/Chapter"},"description":"Every chapter and collection in guide order."}},"required":["productId","chapters"],"additionalProperties":false},"examples":{"list_chapters_and_collections_in_guide_order":{"summary":"List chapters and collections in guide order","value":{"productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","chapters":[{"collectionId":"kn7q65ntqkryzm6y45h5dyxqt0p454y8","productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","name":"Introduction","slug":"introduction","description":null,"kind":"chapter","body":[],"intro":{"coverKicker":"A photographer's field guide","sections":[{"kind":"prose","kicker":"How to use this guide","title":"Timed for the light","deck":"Every spot says when to be there and where to park, so the light and the crowds work for you.","paragraphs":["Each spot lists its best time of day, how crowded it gets and how far it is from the car. Most are short walks; the hikes are marked.","- One day per park? Start with Top picks.\n- Check the park road status before a sunrise drive."],"photoStorageId":"kg2gsfxz27kpg15n437vtmc3zj91qz34"},{"kind":"prose","kicker":"Plan","title":"Before you go","cells":[{"title":"Passes","body":"Each park charges 35 USD per vehicle for 7 days. An annual pass covers both."},{"title":"Seasons","body":"Late May to September suits both parks. Some roads close from November."},{"title":"Driving","body":"Yellowstone to Yosemite is about 1,400 km by road: two long days."},{"title":"Drones","body":"Banned in every US national park."}]},{"kind":"chapters","kicker":"The parks","title":"Two parks, a long drive apart","items":[{"collectionId":"kn7e5r9t3y7v1j5p9p3a7s1d5f9g3h7j","line":"Hot springs, geysers and bison","color":"#b45309"},{"collectionId":"kn73r7x6mp88mxa9swcbshwd3e7zvr39","line":"Granite walls and the valley from above","color":"#1d4ed8"}]},{"kind":"collections","title":"Short on time","items":[{"collectionId":"kn7a2s4d6f8g0h2j4k6k8z0x2c4v6b8n","photoStorageId":"kg29fadcmt160qtrce3h3rm82yc6hhtb"}]}]},"order":1024,"coverUrl":null,"coverStorageId":null,"members":[],"createdAt":1789895640000,"updatedAt":1790586840000},{"collectionId":"kn7e5r9t3y7v1j5p9p3a7s1d5f9g3h7j","productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","name":"Yellowstone","slug":"yellowstone","description":"Hot springs, geysers and bison","kind":"chapter","body":["Yellowstone's hot springs and geysers line the Grand Loop Road, so a car and early starts do most of the work. The spots in this chapter run from Midway Geyser Basin in the southwest to Lamar Valley in the northeast, about three hours apart by road.","Steam decides the photos here. On cold mornings it hides the colors of the hot springs; on warm, dry days it lifts by mid morning. Keep the thermal basins for late morning and the first light for Lamar Valley."],"intro":null,"order":2048,"coverUrl":"https://quiet-heron-512.convex.cloud/api/storage/yellowstone-cover.webp","coverStorageId":"kg2a8c4e0g6j2k8m4p0q6s2v8w4y0a6c","members":[{"spotKey":"01M2Z1G0Y0QG7M2V6N9R3T5W8Y","memberCollectionId":null,"order":1024},{"spotKey":"01M3GYV6A0Y3SYC62RBPEA9S0C","memberCollectionId":null,"order":2048}],"createdAt":1789895640000,"updatedAt":1790586840000},{"collectionId":"kn73r7x6mp88mxa9swcbshwd3e7zvr39","productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","name":"Yosemite","slug":"yosemite","description":"Granite walls and the valley from above","kind":"chapter","body":["Tunnel View, Glacier Point and the trails off Glacier Point Road show the valley from three heights. Glacier Point Road closes to cars in winter, so from November to late May this chapter shrinks to the valley floor.","Sunset belongs to Tunnel View and Taft Point; Glacier Point works from late afternoon into the blue hour."],"intro":null,"order":3072,"coverUrl":null,"coverStorageId":null,"members":[{"spotKey":"01M2Z1G0Y0R2K5P8S1V4X7Z0C3","memberCollectionId":null,"order":1024},{"spotKey":"01M3H2AWH0F9PB64V7QB8QS0MC","memberCollectionId":null,"order":2048},{"spotKey":"01M3H2AXG8GB8YNF4FCEFARFN5","memberCollectionId":null,"order":3072},{"spotKey":"01M3KMNRY0V8ZPTG4HCY75DZFB","memberCollectionId":null,"order":4096},{"spotKey":"01M3H2AYFG8169CVH0JCQY2BN2","memberCollectionId":null,"order":5120}],"createdAt":1789895640000,"updatedAt":1790586840000},{"collectionId":"kn7a2s4d6f8g0h2j4k6k8z0x2c4v6b8n","productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","name":"Top picks","slug":null,"description":"If you only have a day in each park","kind":"collection","body":[],"intro":null,"order":4096,"coverUrl":null,"coverStorageId":null,"members":[{"spotKey":"01M2Z1G0Y0QG7M2V6N9R3T5W8Y","memberCollectionId":null,"order":1024},{"spotKey":"01M2Z1G0Y0R2K5P8S1V4X7Z0C3","memberCollectionId":null,"order":2048},{"spotKey":"01M3H2AWH0F9PB64V7QB8QS0MC","memberCollectionId":null,"order":3072}],"createdAt":1789895640000,"updatedAt":1790586840000},{"collectionId":"kn7hh1xv41qmtn8mk9n7g2wc7qfrfpte","productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","name":"The two parks","slug":null,"description":null,"kind":"collection","body":[],"intro":null,"order":5120,"coverUrl":null,"coverStorageId":null,"members":[{"spotKey":null,"memberCollectionId":"kn7e5r9t3y7v1j5p9p3a7s1d5f9g3h7j","order":1024},{"spotKey":null,"memberCollectionId":"kn73r7x6mp88mxa9swcbshwd3e7zvr39","order":2048}],"createdAt":1789895640000,"updatedAt":1790586840000}]}}}}}},"400":{"description":"Invalid request: invalid_argument","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}},"post":{"operationId":"create_chapter","summary":"Create a chapter or a collection","description":"kind chapter for sections that carry prose (body paragraphs, an intro); kind collection for pure spot sets. Add members afterwards with set_chapter_members.","tags":["chapters"],"x-scope":"write","x-stability":"stable","x-since":"2026-09-17","x-mcp-tool":"create_chapter","parameters":[{"name":"productId","in":"path","required":true,"description":"Id of the guide (a product of type map). From list_guides or create_guide.","schema":{"type":"string","x-sceniq-id":"products"},"example":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Chapter title, e.g. Yellowstone or Bernese Oberland. Cannot be empty."},"body":{"type":"array","items":{"type":"string"},"description":"Ordered prose paragraphs, chapters only, full replacement ([] clears): at most 100, each at most 10,000 characters; empty paragraphs are dropped."},"description":{"type":"string","description":"One-line summary shown on the chapter card. Empty string clears."},"kind":{"enum":["chapter","collection"],"description":"chapter or collection (default collection)."},"slug":{"type":"string","description":"Optional URL slug, unique in the guide: 1 to 63 lowercase letters, digits or hyphens, a letter or digit first (stored lower case). Empty string clears."}},"required":["name"],"additionalProperties":false},"examples":{"a_chapter_with_prose":{"summary":"A chapter with prose","value":{"name":"Yosemite","kind":"chapter","slug":"yosemite","description":"Granite walls and the valley from above","body":["Tunnel View, Glacier Point and the trails off Glacier Point Road show the valley from three heights. Glacier Point Road closes to cars in winter, so from November to late May this chapter shrinks to the valley floor.","Sunset belongs to Tunnel View and Taft Point; Glacier Point works from late afternoon into the blue hour."]}},"a_collection_a_plain_set_of_spots_the_default_kind":{"summary":"A collection: a plain set of spots (the default kind)","value":{"name":"Top picks","description":"If you only have a day in each park"}}}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Chapter"},"examples":{"a_chapter_with_prose":{"summary":"A chapter with prose","value":{"collectionId":"kn73r7x6mp88mxa9swcbshwd3e7zvr39","productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","name":"Yosemite","slug":"yosemite","description":"Granite walls and the valley from above","kind":"chapter","body":["Tunnel View, Glacier Point and the trails off Glacier Point Road show the valley from three heights. Glacier Point Road closes to cars in winter, so from November to late May this chapter shrinks to the valley floor.","Sunset belongs to Tunnel View and Taft Point; Glacier Point works from late afternoon into the blue hour."],"intro":null,"order":3072,"coverUrl":null,"coverStorageId":null,"members":[],"createdAt":1789895640000,"updatedAt":1789895640000}},"a_collection_a_plain_set_of_spots_the_default_kind":{"summary":"A collection: a plain set of spots (the default kind)","value":{"collectionId":"kn7a2s4d6f8g0h2j4k6k8z0x2c4v6b8n","productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","name":"Top picks","slug":null,"description":"If you only have a day in each park","kind":"collection","body":[],"intro":null,"order":4096,"coverUrl":null,"coverStorageId":null,"members":[],"createdAt":1789895640000,"updatedAt":1789895640000}}}}}},"400":{"description":"Invalid request: invalid_argument, invalid_request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}},"invalid_request":{"summary":"The input was refused","value":{"error":{"code":"invalid_request","message":"A writer refused a value: a map link on a host that is not allowed, a title that is too long, a date that does not exist, too many items in a list. The message is the writer's own sentence."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: api_scope_required, forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"api_scope_required":{"summary":"The key lacks a scope","value":{"error":{"code":"api_scope_required","message":"A read-only key called a write operation, or a key without the publish option called publish_changes."}}},"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"413":{"description":"Too large: payload_too_large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"payload_too_large":{"summary":"The request is too large","value":{"error":{"code":"payload_too_large","message":"A JSON body over 2 MB, an image over 6 MB, a batch upload over 19 MB, or an MCP message over 2 MB."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}}},"/chapters/{collectionId}":{"patch":{"operationId":"update_chapter","summary":"Edit a chapter (name, description, prose, cover)","description":"body is a full replacement of the prose paragraphs ([] clears). coverStorageId comes from a photo upload with target=blob; clearCover removes it.","tags":["chapters"],"x-scope":"write","x-stability":"stable","x-since":"2026-09-17","x-mcp-tool":"update_chapter","parameters":[{"name":"collectionId","in":"path","required":true,"description":"Id of the chapter or collection (from list_chapters).","schema":{"type":"string","x-sceniq-id":"collections"},"example":"kn7e5r9t3y7v1j5p9p3a7s1d5f9g3h7j"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"type":"array","items":{"type":"string"},"description":"Ordered prose paragraphs, chapters only, full replacement ([] clears): at most 100, each at most 10,000 characters; empty paragraphs are dropped."},"clearCover":{"type":"boolean","description":"true removes the cover image."},"coverStorageId":{"type":"string","x-sceniq-id":"_storage","description":"Storage id returned by the upload endpoint with target=blob."},"description":{"type":"string","description":"One-line summary shown on the chapter card. Empty string clears."},"expectedUpdatedAt":{"type":"number","description":"Optional staleness guard: the chapter's updatedAt you last read (list_chapters). The write is refused with stale_editor when the chapter changed since."},"kind":{"enum":["chapter","collection"],"description":"chapter or collection. Turning a chapter into a collection clears its body and its front matter (intro), intro photos included."},"name":{"type":"string","description":"Chapter title, e.g. Yellowstone or Bernese Oberland. Cannot be empty."},"slug":{"type":"string","description":"Optional URL slug, unique in the guide: 1 to 63 lowercase letters, digits or hyphens, a letter or digit first (stored lower case). Empty string clears."}},"additionalProperties":false},"examples":{"set_the_cover_from_an_upload_with_target_blob":{"summary":"Set the cover from an upload with target=blob","value":{"coverStorageId":"kg2a8c4e0g6j2k8m4p0q6s2v8w4y0a6c"}},"replace_the_prose_refused_if_someone_else_saved_in_between":{"summary":"Replace the prose, refused if someone else saved in between","value":{"body":["Tunnel View, Glacier Point and the trails off Glacier Point Road show the valley from three heights. Glacier Point Road closes to cars in winter, so from November to late May this chapter shrinks to the valley floor.","Sunset belongs to Tunnel View and Taft Point; Glacier Point works from late afternoon into the blue hour.","In spring the waterfalls run full and Tunnel View gets Bridalveil Fall at its best; by September it can be a trickle."],"expectedUpdatedAt":1790586840000}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"const":true,"description":"Always true: the write went through."},"collectionId":{"type":"string","x-sceniq-id":"collections","description":"The chapter's or collection's id."}},"required":["ok","collectionId"],"additionalProperties":false},"examples":{"set_the_cover_from_an_upload_with_target_blob":{"summary":"Set the cover from an upload with target=blob","value":{"ok":true,"collectionId":"kn7e5r9t3y7v1j5p9p3a7s1d5f9g3h7j"}},"replace_the_prose_refused_if_someone_else_saved_in_between":{"summary":"Replace the prose, refused if someone else saved in between","value":{"ok":true,"collectionId":"kn73r7x6mp88mxa9swcbshwd3e7zvr39"}}}}}},"400":{"description":"Invalid request: invalid_argument, invalid_request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}},"invalid_request":{"summary":"The input was refused","value":{"error":{"code":"invalid_request","message":"A writer refused a value: a map link on a host that is not allowed, a title that is too long, a date that does not exist, too many items in a list. The message is the writer's own sentence."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: api_scope_required, forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"api_scope_required":{"summary":"The key lacks a scope","value":{"error":{"code":"api_scope_required","message":"A read-only key called a write operation, or a key without the publish option called publish_changes."}}},"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"409":{"description":"The row's state refuses it: stale_editor","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"stale_editor":{"summary":"It changed since you read it","value":{"error":{"code":"stale_editor","message":"The row changed after the expectedUpdatedAt you sent (update_chapter, save_sales_page_draft)."}}}}}}},"413":{"description":"Too large: payload_too_large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"payload_too_large":{"summary":"The request is too large","value":{"error":{"code":"payload_too_large","message":"A JSON body over 2 MB, an image over 6 MB, a batch upload over 19 MB, or an MCP message over 2 MB."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}},"delete":{"operationId":"delete_chapter","summary":"Delete a chapter or collection (spots stay)","description":"Removes the section and its member links plus its cover and intro photos. Spots are untouched. Confirm with the creator first.","tags":["chapters"],"x-scope":"write","x-stability":"stable","x-since":"2026-09-17","x-mcp-tool":"delete_chapter","parameters":[{"name":"collectionId","in":"path","required":true,"description":"Id of the chapter or collection.","schema":{"type":"string","x-sceniq-id":"collections"},"example":"kn7bh5h7bj49th4ar47ecatcdqch9npr"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"const":true,"description":"Always true: the write went through."},"collectionId":{"type":"string","x-sceniq-id":"collections","description":"The chapter's or collection's id."},"deleted":{"const":true,"description":"Always true: the row is gone."}},"required":["ok","collectionId","deleted"],"additionalProperties":false},"examples":{"delete_a_chapter_its_spots_stay_in_the_guide":{"summary":"Delete a chapter; its spots stay in the guide","value":{"ok":true,"collectionId":"kn7bh5h7bj49th4ar47ecatcdqch9npr","deleted":true}}}}}},"400":{"description":"Invalid request: invalid_argument, invalid_request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}},"invalid_request":{"summary":"The input was refused","value":{"error":{"code":"invalid_request","message":"A writer refused a value: a map link on a host that is not allowed, a title that is too long, a date that does not exist, too many items in a list. The message is the writer's own sentence."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: api_scope_required, forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"api_scope_required":{"summary":"The key lacks a scope","value":{"error":{"code":"api_scope_required","message":"A read-only key called a write operation, or a key without the publish option called publish_changes."}}},"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"413":{"description":"Too large: payload_too_large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"payload_too_large":{"summary":"The request is too large","value":{"error":{"code":"payload_too_large","message":"A JSON body over 2 MB, an image over 6 MB, a batch upload over 19 MB, or an MCP message over 2 MB."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}}},"/chapters/{collectionId}/members":{"put":{"operationId":"set_chapter_members","summary":"Replace the ordered member list of a chapter","description":"Send the complete desired list in order: [{ spotKey }] entries, or [{ memberCollectionId }] entries to place chapters as cards inside a plain collection. Members not in the list are removed. Atomic.","tags":["chapters"],"x-scope":"write","x-stability":"stable","x-since":"2026-09-17","x-mcp-tool":"set_chapter_members","parameters":[{"name":"collectionId","in":"path","required":true,"description":"Id of the chapter or collection.","schema":{"type":"string","x-sceniq-id":"collections"},"example":"kn73r7x6mp88mxa9swcbshwd3e7zvr39"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"members":{"type":"array","items":{"type":"object","properties":{"spotKey":{"type":"string","description":"A spot of this guide (spotKey from list_spots), listed once. Each entry names exactly one of spotKey or memberCollectionId."},"memberCollectionId":{"type":"string","x-sceniq-id":"collections","description":"A chapter of this guide (kind chapter) shown as a card, listed once. Only a plain collection can hold chapters."}},"additionalProperties":false},"description":"Ordered list of { spotKey } or { memberCollectionId } objects, at most 500."}},"required":["members"],"additionalProperties":false},"examples":{"set_a_chapter_s_spots_in_order":{"summary":"Set a chapter's spots in order","value":{"members":[{"spotKey":"01M2Z1G0Y0R2K5P8S1V4X7Z0C3"},{"spotKey":"01M3H2AWH0F9PB64V7QB8QS0MC"},{"spotKey":"01M3H2AXG8GB8YNF4FCEFARFN5"},{"spotKey":"01M3KMNRY0V8ZPTG4HCY75DZFB"},{"spotKey":"01M3H2AYFG8169CVH0JCQY2BN2"}]}},"place_chapters_as_cards_inside_a_collection":{"summary":"Place chapters as cards inside a collection","value":{"members":[{"memberCollectionId":"kn7e5r9t3y7v1j5p9p3a7s1d5f9g3h7j"},{"memberCollectionId":"kn73r7x6mp88mxa9swcbshwd3e7zvr39"}]}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"const":true,"description":"Always true: the write went through."},"collectionId":{"type":"string","x-sceniq-id":"collections","description":"The chapter's or collection's id."},"members":{"type":"number","description":"How many members the chapter now has."}},"required":["ok","collectionId","members"],"additionalProperties":false},"examples":{"set_a_chapter_s_spots_in_order":{"summary":"Set a chapter's spots in order","value":{"ok":true,"collectionId":"kn73r7x6mp88mxa9swcbshwd3e7zvr39","members":5}},"place_chapters_as_cards_inside_a_collection":{"summary":"Place chapters as cards inside a collection","value":{"ok":true,"collectionId":"kn7hh1xv41qmtn8mk9n7g2wc7qfrfpte","members":2}}}}}},"400":{"description":"Invalid request: invalid_argument, invalid_request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}},"invalid_request":{"summary":"The input was refused","value":{"error":{"code":"invalid_request","message":"A writer refused a value: a map link on a host that is not allowed, a title that is too long, a date that does not exist, too many items in a list. The message is the writer's own sentence."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: api_scope_required, forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"api_scope_required":{"summary":"The key lacks a scope","value":{"error":{"code":"api_scope_required","message":"A read-only key called a write operation, or a key without the publish option called publish_changes."}}},"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"413":{"description":"Too large: payload_too_large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"payload_too_large":{"summary":"The request is too large","value":{"error":{"code":"payload_too_large","message":"A JSON body over 2 MB, an image over 6 MB, a batch upload over 19 MB, or an MCP message over 2 MB."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}}},"/chapters/{collectionId}/intro":{"put":{"operationId":"set_chapter_intro","summary":"Set the structured front matter of an intro chapter","description":"Editorial sections the viewer renders as the front matter: { coverKicker?, coverTitle? (default: the guide name), coverAuthor? (byline name, default: the creator), coverAuthorPhotoStorageId?, sections: [{ kind?: prose|chapters|collections, kicker?, title, deck?, paragraphs? (lines starting with \"- \" render as a list), cells?: [{ title, body }], photoStorageId?, photoCredit?, items? }] }. items only on chapters/collections sections, one per collectionId: chapters rows take { line?, color? (#rrggbb) }, collections cards take { title?, photoStorageId?, photoCredit? }. Rows and cards still derive from the guide; items only dress them. Photo ids come from the media upload endpoint with target=blob. Null clears. Chapters only.","tags":["chapters"],"x-scope":"write","x-stability":"stable","x-since":"2026-09-17","x-mcp-tool":"set_chapter_intro","parameters":[{"name":"collectionId","in":"path","required":true,"description":"Id of the chapter.","schema":{"type":"string","x-sceniq-id":"collections"},"example":"kn7q65ntqkryzm6y45h5dyxqt0p454y8"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"intro":{"anyOf":[{"$ref":"#/components/schemas/ChapterIntro"},{"type":"null"}],"description":"The front matter object, or null to clear."},"expectedUpdatedAt":{"type":"number","description":"Optional staleness guard: the chapter's updatedAt you last read (list_chapters). The write is refused with stale_editor when the chapter changed since."}},"required":["intro"],"additionalProperties":false},"examples":{"write_the_guide_s_front_matter":{"summary":"Write the guide's front matter","value":{"intro":{"coverKicker":"A photographer's field guide","sections":[{"kind":"prose","kicker":"How to use this guide","title":"Timed for the light","deck":"Every spot says when to be there and where to park, so the light and the crowds work for you.","paragraphs":["Each spot lists its best time of day, how crowded it gets and how far it is from the car. Most are short walks; the hikes are marked.","- One day per park? Start with Top picks.\n- Check the park road status before a sunrise drive."],"photoStorageId":"kg2gsfxz27kpg15n437vtmc3zj91qz34"},{"kind":"prose","kicker":"Plan","title":"Before you go","cells":[{"title":"Passes","body":"Each park charges 35 USD per vehicle for 7 days. An annual pass covers both."},{"title":"Seasons","body":"Late May to September suits both parks. Some roads close from November."},{"title":"Driving","body":"Yellowstone to Yosemite is about 1,400 km by road: two long days."},{"title":"Drones","body":"Banned in every US national park."}]},{"kind":"chapters","kicker":"The parks","title":"Two parks, a long drive apart","items":[{"collectionId":"kn7e5r9t3y7v1j5p9p3a7s1d5f9g3h7j","line":"Hot springs, geysers and bison","color":"#b45309"},{"collectionId":"kn73r7x6mp88mxa9swcbshwd3e7zvr39","line":"Granite walls and the valley from above","color":"#1d4ed8"}]},{"kind":"collections","title":"Short on time","items":[{"collectionId":"kn7a2s4d6f8g0h2j4k6k8z0x2c4v6b8n","photoStorageId":"kg29fadcmt160qtrce3h3rm82yc6hhtb"}]}]},"expectedUpdatedAt":1789895640000}},"clear_the_front_matter":{"summary":"Clear the front matter","value":{"intro":null}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"const":true,"description":"Always true: the write went through."},"collectionId":{"type":"string","x-sceniq-id":"collections","description":"The chapter's or collection's id."}},"required":["ok","collectionId"],"additionalProperties":false},"examples":{"write_the_guide_s_front_matter":{"summary":"Write the guide's front matter","value":{"ok":true,"collectionId":"kn7q65ntqkryzm6y45h5dyxqt0p454y8"}},"clear_the_front_matter":{"summary":"Clear the front matter","value":{"ok":true,"collectionId":"kn7q65ntqkryzm6y45h5dyxqt0p454y8"}}}}}},"400":{"description":"Invalid request: invalid_argument, invalid_request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}},"invalid_request":{"summary":"The input was refused","value":{"error":{"code":"invalid_request","message":"A writer refused a value: a map link on a host that is not allowed, a title that is too long, a date that does not exist, too many items in a list. The message is the writer's own sentence."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: api_scope_required, forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"api_scope_required":{"summary":"The key lacks a scope","value":{"error":{"code":"api_scope_required","message":"A read-only key called a write operation, or a key without the publish option called publish_changes."}}},"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"409":{"description":"The row's state refuses it: stale_editor","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"stale_editor":{"summary":"It changed since you read it","value":{"error":{"code":"stale_editor","message":"The row changed after the expectedUpdatedAt you sent (update_chapter, save_sales_page_draft)."}}}}}}},"413":{"description":"Too large: payload_too_large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"payload_too_large":{"summary":"The request is too large","value":{"error":{"code":"payload_too_large","message":"A JSON body over 2 MB, an image over 6 MB, a batch upload over 19 MB, or an MCP message over 2 MB."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}}},"/chapters/{collectionId}/position":{"put":{"operationId":"reorder_chapter","summary":"Move a chapter between two neighbours","description":"Place the chapter after previousId and before nextId (either may be omitted for the ends).","tags":["chapters"],"x-scope":"write","x-stability":"stable","x-since":"2026-09-17","x-mcp-tool":"reorder_chapter","parameters":[{"name":"collectionId","in":"path","required":true,"description":"Id of the chapter to move.","schema":{"type":"string","x-sceniq-id":"collections"},"example":"kn7a2s4d6f8g0h2j4k6k8z0x2c4v6b8n"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"nextId":{"type":"string","x-sceniq-id":"collections","description":"Id of the chapter that should follow it."},"previousId":{"type":"string","x-sceniq-id":"collections","description":"Id of the chapter that should precede it."}},"additionalProperties":false},"examples":{"move_top_picks_between_the_introduction_and_yellowstone":{"summary":"Move Top picks between the introduction and Yellowstone","value":{"previousId":"kn7q65ntqkryzm6y45h5dyxqt0p454y8","nextId":"kn7e5r9t3y7v1j5p9p3a7s1d5f9g3h7j"}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"const":true,"description":"Always true: the write went through."},"collectionId":{"type":"string","x-sceniq-id":"collections","description":"The chapter's or collection's id."}},"required":["ok","collectionId"],"additionalProperties":false},"examples":{"move_top_picks_between_the_introduction_and_yellowstone":{"summary":"Move Top picks between the introduction and Yellowstone","value":{"ok":true,"collectionId":"kn7a2s4d6f8g0h2j4k6k8z0x2c4v6b8n"}}}}}},"400":{"description":"Invalid request: invalid_argument, invalid_request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}},"invalid_request":{"summary":"The input was refused","value":{"error":{"code":"invalid_request","message":"A writer refused a value: a map link on a host that is not allowed, a title that is too long, a date that does not exist, too many items in a list. The message is the writer's own sentence."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: api_scope_required, forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"api_scope_required":{"summary":"The key lacks a scope","value":{"error":{"code":"api_scope_required","message":"A read-only key called a write operation, or a key without the publish option called publish_changes."}}},"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"413":{"description":"Too large: payload_too_large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"payload_too_large":{"summary":"The request is too large","value":{"error":{"code":"payload_too_large","message":"A JSON body over 2 MB, an image over 6 MB, a batch upload over 19 MB, or an MCP message over 2 MB."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}}},"/guides/{productId}/routes":{"get":{"operationId":"list_routes","summary":"Routes (hikes, approaches) with their spot and facility links","description":"Every route with stats, transit notes, equipment, sources and the ordered spot and facility links.","tags":["routes"],"x-scope":"read","x-stability":"stable","x-since":"2026-09-17","x-mcp-tool":"list_routes","parameters":[{"name":"productId","in":"path","required":true,"description":"Id of the guide (a product of type map). From list_guides or create_guide.","schema":{"type":"string","x-sceniq-id":"products"},"example":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"productId":{"type":"string","x-sceniq-id":"products","description":"The guide's id."},"routes":{"type":"array","items":{"$ref":"#/components/schemas/Route"},"description":"Every route, by name."}},"required":["productId","routes"],"additionalProperties":false},"examples":{"every_route_of_a_guide_with_its_spot_and_place_links":{"summary":"Every route of a guide with its spot and place links","value":{"productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","routes":[{"routeId":"kx7f2h8j4k0k6z2x8c4v0b6n2m8q4w0e","name":"Fairy Falls trail to the Grand Prismatic overlook","activity":"hike","sacGrade":"Class 1","gradeScale":"yds","effortLabel":"Easy","durationMin":45,"gainM":35,"descentM":35,"distanceKm":2,"start":"Fairy Falls trailhead on the Grand Loop Road, 1.6 km south of Midway Geyser Basin","startMapsUrl":"https://maps.apple.com/?ll=44.5156,-110.8326&q=Fairy%20Falls%20Trailhead","transit":[{"mode":"car","note":"Park at the Fairy Falls trailhead lot, which fills by 09:30 in July and August. No public transport runs in the park."},{"mode":"plane","note":"Yellowstone Airport (WYS) in West Yellowstone, 45 km by road, has flights from June to September."}],"description":"A flat kilometer on the old Fountain Freight Road, then a short climb to a platform above Grand Prismatic Spring. Go mid morning on a warm day, once the steam has lifted.","equipment":["Bear spray","A warm layer for the morning"],"sources":["https://www.nps.gov/places/000/grand-prismatic-spring.htm","GPX recorded by Mara Lindgren on 2026-09-14"],"extraProps":[{"label":"Dogs","value":"Not allowed on park trails"}],"track":{"coordinates":[[-110.8326,44.5156,2181],[-110.8349,44.517,2182],[-110.8372,44.5183,2183],[-110.8391,44.519,2186],[-110.8402,44.5196,2201],[-110.8406,44.5199,2214]],"source":"gpx","fileName":"fairy-falls-overlook-2026-09-14.gpx"},"status":null,"season":{"months":[4,5,6,7,8,9,10],"closureNote":"Park roads close to cars from early November to mid April; the trailhead is then reached by snowcoach only.","statusUrl":"https://www.nps.gov/yell/planyourvisit/conditions.htm"},"variants":[{"name":"On to Fairy Falls","extraKm":6.8,"extraMin":120,"purpose":"A 60 m waterfall 3.4 km further along the same trail, quiet before 09:00."}],"stages":[],"segments":[{"name":"Fountain Freight Road","km":1.1,"accessNote":"Flat gravel road over the Firehole River, closed to cars. Bikes allowed."},{"name":"Overlook spur","km":0.3,"accessNote":"Hikers only. The one climb of the route."}],"shape":"out_and_back","durationBasis":"round_trip","ascentMin":null,"descentMin":null,"sourceGrade":"Easy","figureSources":[{"field":"distanceKm","kind":"sourced","url":"https://www.nps.gov/places/000/grand-prismatic-spring.htm"},{"field":"gainM","kind":"computed","note":"From the GPX, smoothed"},{"field":"durationMin","kind":"computed","note":"Walking time without the stop on the platform"}],"reviewNotes":"The NPS page gives no elevation gain; the figure comes from the GPX.","factsCheckedOn":"2026-09-20","reviewBy":"2027-04-01","createdAt":1789895640000,"updatedAt":1790586840000,"spots":[{"spotKey":"01M2Z1G0Y0QG7M2V6N9R3T5W8Y","order":1024,"quickest":false,"role":"required"}],"facilities":[{"facilityId":"km7d4f6g8h0j2k4k6z8x0c2v4b6n8m0q","order":1024}]},{"routeId":"kx7r4t6y8v0j2p4p6a8s0d2f4g6h8j0k","name":"Inspiration Point from Tunnel View","activity":"hike","sacGrade":"Class 1","gradeScale":"yds","effortLabel":"Moderate","durationMin":120,"gainM":305,"descentM":305,"distanceKm":4.2,"start":"Pohono Trail sign at the Tunnel View parking","startMapsUrl":"https://www.google.com/maps/search/?api=1&query=37.7156,-119.677","transit":[],"description":"Steep switchbacks up the Pohono Trail to a quieter, higher version of the Tunnel View frame. Most of the climb is in full sun.","equipment":["Two liters of water per person"],"sources":["GPX recorded by Mara Lindgren on 2026-06-11"],"extraProps":[],"track":null,"status":null,"season":null,"variants":[],"stages":[],"segments":[],"shape":"out_and_back","durationBasis":"round_trip","ascentMin":null,"descentMin":null,"sourceGrade":null,"figureSources":[],"reviewNotes":null,"factsCheckedOn":null,"reviewBy":null,"createdAt":1789895640000,"updatedAt":1790586840000,"spots":[{"spotKey":"01M2Z1G0Y0R2K5P8S1V4X7Z0C3","order":1024,"quickest":false,"role":"optional"}],"facilities":[]}]}}}}}},"400":{"description":"Invalid request: invalid_argument","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}},"post":{"operationId":"create_route","summary":"Add a route (how to get there)","description":"Planning facts the creator vouches for: route type, grade and its scale, effort, duration, gain, distance, trailhead, transit per mode, equipment ([] means explicitly none), sources (where the numbers come from) and the line from the creator's GPX or KML. Link spots with set_route_spots afterwards.","tags":["routes"],"x-scope":"write","x-stability":"stable","x-since":"2026-09-17","x-mcp-tool":"create_route","parameters":[{"name":"productId","in":"path","required":true,"description":"Id of the guide (a product of type map). From list_guides or create_guide.","schema":{"type":"string","x-sceniq-id":"products"},"example":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"activity":{"type":"string","description":"hike, walk, bike, drive, ski or paddle. A route without one is a hike; empty string clears."},"ascentMin":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Minutes up, when the source gives up and down separately. null clears."},"descentM":{"type":"number","description":"Descent in meters, 0 or more. Never derived from gainM: give it when the source does."},"descentMin":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Minutes down. null clears."},"description":{"type":"string","description":"The route in the creator's words, shown on the route card. Empty string clears."},"distanceKm":{"type":"number","description":"Distance in kilometers, 0 or more."},"durationBasis":{"anyOf":[{"enum":["round_trip","one_way","ascent"]},{"type":"null"}],"description":"What durationMin counts: round_trip (the default), one_way or ascent. null clears."},"durationMin":{"type":"number","description":"Duration in minutes, 0 or more; durationBasis says what it counts (round trip unless set)."},"effortLabel":{"type":"string","description":"Easy, Moderate, Hard (free text). Empty string clears."},"equipment":{"type":"array","items":{"type":"string"},"description":"Gear, at most 50 items; [] means explicitly no special gear (shown as None), absent means unknown."},"extraProps":{"type":"array","items":{"$ref":"#/components/schemas/ExtraProp"},"description":"Free label and value rows shown on the card, full replacement ([] clears), at most 24: [{ label (at most 60 characters), value (at most 500) }]. A row with both sides empty is dropped, a half-empty one refused."},"factsCheckedOn":{"type":"string","description":"The day the facts were last checked against their sources (YYYY-MM-DD). Empty string clears."},"figureSources":{"type":"array","items":{"$ref":"#/components/schemas/FigureSource"},"description":"Where each number comes from, full replacement: [{ field: durationMin|distanceKm|gainM|descentM|sacGrade, kind: sourced|computed, url?, note? }]."},"gainM":{"type":"number","description":"Elevation gain in meters, 0 or more."},"gradeScale":{"type":"string","description":"sac, via_ferrata, cai, yds, mtb, whitewater or other. A route without one uses sac; empty string clears."},"name":{"type":"string","description":"Route name, e.g. Fairy Falls trail or Oeschinensee loop. Without one the apps show Hike from <start> (Drive from, Bike ride from ... by activity), or Route N when there is no start either. Empty string clears."},"reviewBy":{"type":"string","description":"The day the facts need a new check (YYYY-MM-DD), e.g. when a season, fare or timetable runs out. get_guide_readiness and get_publish_status warn once it has passed. Empty string clears."},"reviewNotes":{"type":"string","description":"Notes for the creator's review (why a value was chosen, what could not be verified). Never shown to buyers; get_guide_readiness lists them. Empty string clears."},"sacGrade":{"type":"string","description":"The grade as written in gradeScale, e.g. T2 (SAC), EE (CAI), Class 3 (US), S2 (mountain bike). Empty string clears."},"season":{"anyOf":[{"$ref":"#/components/schemas/RouteSeason"},{"type":"null"}],"description":"When the route can be walked, null clears: { months? [1-12], closureNote? (stairs chained November to April), statusUrl? }. Buyers opening it out of season see the closure."},"segments":{"type":"array","items":{"$ref":"#/components/schemas/RouteSegment"},"description":"Sections with their own access (free to Scout Lookout, permit for the chains): [{ name, km?, accessNote? }]."},"shape":{"anyOf":[{"enum":["loop","out_and_back","one_way"]},{"type":"null"}],"description":"loop, out_and_back or one_way. null clears."},"sourceGrade":{"type":"string","description":"The source's own grade (Easy on the park page) next to your effortLabel. Empty string clears."},"sources":{"type":"array","items":{"type":"string"},"description":"Where the facts come from, full replacement ([] clears), at most 25 entries: links to official trail pages or plain text (the creator's GPX). Buyers see them under Sources, links by their host."},"stages":{"type":"array","items":{"$ref":"#/components/schemas/RouteStage"},"description":"Days or legs of a trek, full replacement: [{ name, km?, min?, gainM?, note? }]."},"start":{"type":"string","description":"Trailhead or starting point in words. Empty string clears."},"startMapsUrl":{"type":"string","description":"Map link to the trailhead: https on Google Maps, Apple Maps, Swisstopo, OpenStreetMap or SchweizMobil, or a geo: URI. Empty string clears."},"status":{"anyOf":[{"$ref":"#/components/schemas/StatusNotice"},{"type":"null"}],"description":"Closure or works notice, null clears: { state: open|partly_closed|closed|reopening, note?, since?, until? (the day the state is expected to end; buyers stop seeing the notice after it), sourceUrl?, checkedOn? }. reopening with until means reopens on that day."},"track":{"$ref":"#/components/schemas/RouteTrack","description":"The route line from the creator's GPX or KML: { coordinates: [[lon, lat] or [lon, lat, ele]], source: gpx|kml, fileName }. 2 to 1,000 points; simplify long recordings first."},"transit":{"type":"array","items":{"$ref":"#/components/schemas/TransitNote"},"description":"Transit notes shown under Transit on the route card, full replacement ([] clears), at most 20: [{ mode: train|bus|cable_car|car|boat|ferry|plane, note }]. Rows with an empty note are dropped."},"variants":{"type":"array","items":{"$ref":"#/components/schemas/RouteVariant"},"description":"Alternatives, full replacement: [{ name, start?, extraKm?, extraMin?, purpose? }]."}},"additionalProperties":false},"examples":{"add_a_hike_with_its_grade_figures_season_sources_and_gpx_line":{"summary":"Add a hike with its grade, figures, season, sources and GPX line","value":{"name":"Fairy Falls trail to the Grand Prismatic overlook","activity":"hike","sacGrade":"Class 1","gradeScale":"yds","sourceGrade":"Easy","effortLabel":"Easy","durationMin":45,"durationBasis":"round_trip","distanceKm":2,"gainM":35,"descentM":35,"shape":"out_and_back","start":"Fairy Falls trailhead on the Grand Loop Road, 1.6 km south of Midway Geyser Basin","startMapsUrl":"https://maps.apple.com/?ll=44.5156,-110.8326&q=Fairy%20Falls%20Trailhead","description":"A flat kilometer on the old Fountain Freight Road, then a short climb to a platform above Grand Prismatic Spring. Go mid morning on a warm day, once the steam has lifted.","transit":[{"mode":"car","note":"Park at the Fairy Falls trailhead lot, which fills by 09:30 in July and August. No public transport runs in the park."},{"mode":"plane","note":"Yellowstone Airport (WYS) in West Yellowstone, 45 km by road, has flights from June to September."}],"equipment":["Bear spray","A warm layer for the morning"],"sources":["https://www.nps.gov/places/000/grand-prismatic-spring.htm","GPX recorded by Mara Lindgren on 2026-09-14"],"extraProps":[{"label":"Dogs","value":"Not allowed on park trails"}],"season":{"months":[4,5,6,7,8,9,10],"closureNote":"Park roads close to cars from early November to mid April; the trailhead is then reached by snowcoach only.","statusUrl":"https://www.nps.gov/yell/planyourvisit/conditions.htm"},"variants":[{"name":"On to Fairy Falls","extraKm":6.8,"extraMin":120,"purpose":"A 60 m waterfall 3.4 km further along the same trail, quiet before 09:00."}],"segments":[{"name":"Fountain Freight Road","km":1.1,"accessNote":"Flat gravel road over the Firehole River, closed to cars. Bikes allowed."},{"name":"Overlook spur","km":0.3,"accessNote":"Hikers only. The one climb of the route."}],"figureSources":[{"field":"distanceKm","kind":"sourced","url":"https://www.nps.gov/places/000/grand-prismatic-spring.htm"},{"field":"gainM","kind":"computed","note":"From the GPX, smoothed"},{"field":"durationMin","kind":"computed","note":"Walking time without the stop on the platform"}],"track":{"coordinates":[[-110.8326,44.5156,2181],[-110.8349,44.517,2182],[-110.8372,44.5183,2183],[-110.8391,44.519,2186],[-110.8402,44.5196,2201],[-110.8406,44.5199,2214]],"source":"gpx","fileName":"fairy-falls-overlook-2026-09-14.gpx"},"reviewNotes":"The NPS page gives no elevation gain; the figure comes from the GPX.","factsCheckedOn":"2026-09-20","reviewBy":"2027-04-01"}},"a_short_drive_with_only_the_basics_everything_else_comes_back_null_or_empty":{"summary":"A short drive with only the basics: everything else comes back null or empty","value":{"name":"Wawona Road from Yosemite Valley to Tunnel View","activity":"drive","durationMin":10,"durationBasis":"one_way","distanceKm":6.5}}}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteWrite"},"examples":{"add_a_hike_with_its_grade_figures_season_sources_and_gpx_line":{"summary":"Add a hike with its grade, figures, season, sources and GPX line","value":{"routeId":"kx7f2h8j4k0k6z2x8c4v0b6n2m8q4w0e","name":"Fairy Falls trail to the Grand Prismatic overlook","activity":"hike","sacGrade":"Class 1","gradeScale":"yds","effortLabel":"Easy","durationMin":45,"gainM":35,"descentM":35,"distanceKm":2,"start":"Fairy Falls trailhead on the Grand Loop Road, 1.6 km south of Midway Geyser Basin","startMapsUrl":"https://maps.apple.com/?ll=44.5156,-110.8326&q=Fairy%20Falls%20Trailhead","transit":[{"mode":"car","note":"Park at the Fairy Falls trailhead lot, which fills by 09:30 in July and August. No public transport runs in the park."},{"mode":"plane","note":"Yellowstone Airport (WYS) in West Yellowstone, 45 km by road, has flights from June to September."}],"description":"A flat kilometer on the old Fountain Freight Road, then a short climb to a platform above Grand Prismatic Spring. Go mid morning on a warm day, once the steam has lifted.","equipment":["Bear spray","A warm layer for the morning"],"sources":["https://www.nps.gov/places/000/grand-prismatic-spring.htm","GPX recorded by Mara Lindgren on 2026-09-14"],"extraProps":[{"label":"Dogs","value":"Not allowed on park trails"}],"track":{"coordinates":[[-110.8326,44.5156,2181],[-110.8349,44.517,2182],[-110.8372,44.5183,2183],[-110.8391,44.519,2186],[-110.8402,44.5196,2201],[-110.8406,44.5199,2214]],"source":"gpx","fileName":"fairy-falls-overlook-2026-09-14.gpx"},"status":null,"season":{"months":[4,5,6,7,8,9,10],"closureNote":"Park roads close to cars from early November to mid April; the trailhead is then reached by snowcoach only.","statusUrl":"https://www.nps.gov/yell/planyourvisit/conditions.htm"},"variants":[{"name":"On to Fairy Falls","extraKm":6.8,"extraMin":120,"purpose":"A 60 m waterfall 3.4 km further along the same trail, quiet before 09:00."}],"stages":[],"segments":[{"name":"Fountain Freight Road","km":1.1,"accessNote":"Flat gravel road over the Firehole River, closed to cars. Bikes allowed."},{"name":"Overlook spur","km":0.3,"accessNote":"Hikers only. The one climb of the route."}],"shape":"out_and_back","durationBasis":"round_trip","ascentMin":null,"descentMin":null,"sourceGrade":"Easy","figureSources":[{"field":"distanceKm","kind":"sourced","url":"https://www.nps.gov/places/000/grand-prismatic-spring.htm"},{"field":"gainM","kind":"computed","note":"From the GPX, smoothed"},{"field":"durationMin","kind":"computed","note":"Walking time without the stop on the platform"}],"reviewNotes":"The NPS page gives no elevation gain; the figure comes from the GPX.","factsCheckedOn":"2026-09-20","reviewBy":"2027-04-01","createdAt":1789895640000,"updatedAt":1789895640000,"spots":[],"facilities":[]}},"a_short_drive_with_only_the_basics_everything_else_comes_back_null_or_empty":{"summary":"A short drive with only the basics: everything else comes back null or empty","value":{"routeId":"kx7c5v7b9n1m3q5w7e9r1t3y5v7j9p1p","name":"Wawona Road from Yosemite Valley to Tunnel View","activity":"drive","sacGrade":null,"gradeScale":null,"effortLabel":null,"durationMin":10,"gainM":null,"descentM":null,"distanceKm":6.5,"start":null,"startMapsUrl":null,"transit":[],"description":null,"equipment":null,"sources":[],"extraProps":[],"track":null,"status":null,"season":null,"variants":[],"stages":[],"segments":[],"shape":null,"durationBasis":"one_way","ascentMin":null,"descentMin":null,"sourceGrade":null,"figureSources":[],"reviewNotes":null,"factsCheckedOn":null,"reviewBy":null,"createdAt":1790673240000,"updatedAt":1790673240000,"spots":[],"facilities":[]}}}}}},"400":{"description":"Invalid request: invalid_argument, invalid_request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}},"invalid_request":{"summary":"The input was refused","value":{"error":{"code":"invalid_request","message":"A writer refused a value: a map link on a host that is not allowed, a title that is too long, a date that does not exist, too many items in a list. The message is the writer's own sentence."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: api_scope_required, forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"api_scope_required":{"summary":"The key lacks a scope","value":{"error":{"code":"api_scope_required","message":"A read-only key called a write operation, or a key without the publish option called publish_changes."}}},"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"413":{"description":"Too large: payload_too_large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"payload_too_large":{"summary":"The request is too large","value":{"error":{"code":"payload_too_large","message":"A JSON body over 2 MB, an image over 6 MB, a batch upload over 19 MB, or an MCP message over 2 MB."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}}},"/routes/{routeId}":{"patch":{"operationId":"update_route","summary":"Edit a route","description":"Only sent fields change. Strings clear on empty string, numeric stats and objects clear on null, arrays are full replacements, track null removes the line.","tags":["routes"],"x-scope":"write","x-stability":"stable","x-since":"2026-09-17","x-mcp-tool":"update_route","parameters":[{"name":"routeId","in":"path","required":true,"description":"Id of the route (from list_routes).","schema":{"type":"string","x-sceniq-id":"routes"},"example":"kx7f2h8j4k0k6z2x8c4v0b6n2m8q4w0e"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"activity":{"type":"string","description":"hike, walk, bike, drive, ski or paddle. A route without one is a hike; empty string clears."},"ascentMin":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Minutes up, when the source gives up and down separately. null clears."},"descentM":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Descent in meters, 0 or more. Never derived from gainM: give it when the source does. null clears."},"descentMin":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Minutes down. null clears."},"description":{"type":"string","description":"The route in the creator's words, shown on the route card. Empty string clears."},"distanceKm":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Distance in kilometers, 0 or more. null clears."},"durationBasis":{"anyOf":[{"enum":["round_trip","one_way","ascent"]},{"type":"null"}],"description":"What durationMin counts: round_trip (the default), one_way or ascent. null clears."},"durationMin":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Duration in minutes, 0 or more; durationBasis says what it counts (round trip unless set). null clears."},"effortLabel":{"type":"string","description":"Easy, Moderate, Hard (free text). Empty string clears."},"equipment":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"description":"Gear, full replacement, at most 50 items; [] means explicitly no special gear (shown as None), null clears back to unknown."},"extraProps":{"type":"array","items":{"$ref":"#/components/schemas/ExtraProp"},"description":"Free label and value rows shown on the card, full replacement ([] clears), at most 24: [{ label (at most 60 characters), value (at most 500) }]. A row with both sides empty is dropped, a half-empty one refused."},"factsCheckedOn":{"type":"string","description":"The day the facts were last checked against their sources (YYYY-MM-DD). Empty string clears."},"figureSources":{"type":"array","items":{"$ref":"#/components/schemas/FigureSource"},"description":"Where each number comes from, full replacement: [{ field: durationMin|distanceKm|gainM|descentM|sacGrade, kind: sourced|computed, url?, note? }]."},"gainM":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Elevation gain in meters, 0 or more. null clears."},"gradeScale":{"type":"string","description":"sac, via_ferrata, cai, yds, mtb, whitewater or other. A route without one uses sac; empty string clears."},"name":{"type":"string","description":"Route name, e.g. Fairy Falls trail or Oeschinensee loop. Without one the apps show Hike from <start> (Drive from, Bike ride from ... by activity), or Route N when there is no start either. Empty string clears."},"reviewBy":{"type":"string","description":"The day the facts need a new check (YYYY-MM-DD), e.g. when a season, fare or timetable runs out. get_guide_readiness and get_publish_status warn once it has passed. Empty string clears."},"reviewNotes":{"type":"string","description":"Notes for the creator's review (why a value was chosen, what could not be verified). Never shown to buyers; get_guide_readiness lists them. Empty string clears."},"sacGrade":{"type":"string","description":"The grade as written in gradeScale, e.g. T2 (SAC), EE (CAI), Class 3 (US), S2 (mountain bike). Empty string clears."},"season":{"anyOf":[{"$ref":"#/components/schemas/RouteSeason"},{"type":"null"}],"description":"When the route can be walked, null clears: { months? [1-12], closureNote? (stairs chained November to April), statusUrl? }. Buyers opening it out of season see the closure."},"segments":{"type":"array","items":{"$ref":"#/components/schemas/RouteSegment"},"description":"Sections with their own access (free to Scout Lookout, permit for the chains): [{ name, km?, accessNote? }]."},"shape":{"anyOf":[{"enum":["loop","out_and_back","one_way"]},{"type":"null"}],"description":"loop, out_and_back or one_way. null clears."},"sourceGrade":{"type":"string","description":"The source's own grade (Easy on the park page) next to your effortLabel. Empty string clears."},"sources":{"type":"array","items":{"type":"string"},"description":"Where the facts come from, full replacement ([] clears), at most 25 entries: links to official trail pages or plain text (the creator's GPX). Buyers see them under Sources, links by their host."},"stages":{"type":"array","items":{"$ref":"#/components/schemas/RouteStage"},"description":"Days or legs of a trek, full replacement: [{ name, km?, min?, gainM?, note? }]."},"start":{"type":"string","description":"Trailhead or starting point in words. Empty string clears."},"startMapsUrl":{"type":"string","description":"Map link to the trailhead: https on Google Maps, Apple Maps, Swisstopo, OpenStreetMap or SchweizMobil, or a geo: URI. Empty string clears."},"status":{"anyOf":[{"$ref":"#/components/schemas/StatusNotice"},{"type":"null"}],"description":"Closure or works notice, null clears: { state: open|partly_closed|closed|reopening, note?, since?, until? (the day the state is expected to end; buyers stop seeing the notice after it), sourceUrl?, checkedOn? }. reopening with until means reopens on that day."},"track":{"anyOf":[{"$ref":"#/components/schemas/RouteTrack"},{"type":"null"}],"description":"The route line (see create_route), replaced whole; null removes it."},"transit":{"type":"array","items":{"$ref":"#/components/schemas/TransitNote"},"description":"Transit notes shown under Transit on the route card, full replacement ([] clears), at most 20: [{ mode: train|bus|cable_car|car|boat|ferry|plane, note }]. Rows with an empty note are dropped."},"variants":{"type":"array","items":{"$ref":"#/components/schemas/RouteVariant"},"description":"Alternatives, full replacement: [{ name, start?, extraKm?, extraMin?, purpose? }]."}},"additionalProperties":false},"examples":{"post_a_closure_notice_with_the_day_the_spur_reopens":{"summary":"Post a closure notice with the day the spur reopens","value":{"status":{"state":"reopening","note":"The overlook spur and platform are closed for repairs. The trail to Fairy Falls stays open.","since":"2026-09-28","until":"2026-10-16","sourceUrl":"https://www.nps.gov/yell/planyourvisit/conditions.htm","checkedOn":"2026-09-29"},"reviewBy":"2026-10-17"}},"remove_the_line_and_the_figures_computed_from_it_null_clears":{"summary":"Remove the line and the figures computed from it (null clears)","value":{"track":null,"gainM":null,"descentM":null,"figureSources":[{"field":"distanceKm","kind":"sourced","url":"https://www.nps.gov/places/000/grand-prismatic-spring.htm"}],"reviewNotes":"The GPX was from another trail; gain removed until a new recording."}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"const":true,"description":"Always true: the write went through."},"routeId":{"type":"string","x-sceniq-id":"routes","description":"The route's id."},"warnings":{"type":"array","items":{"type":"string"},"description":"Notes about things the write accepted but you should look at (a plain http link). Present only when there are any."}},"required":["ok","routeId"],"additionalProperties":false},"examples":{"post_a_closure_notice_with_the_day_the_spur_reopens":{"summary":"Post a closure notice with the day the spur reopens","value":{"ok":true,"routeId":"kx7f2h8j4k0k6z2x8c4v0b6n2m8q4w0e"}},"remove_the_line_and_the_figures_computed_from_it_null_clears":{"summary":"Remove the line and the figures computed from it (null clears)","value":{"ok":true,"routeId":"kx7f2h8j4k0k6z2x8c4v0b6n2m8q4w0e"}}}}}},"400":{"description":"Invalid request: invalid_argument, invalid_request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}},"invalid_request":{"summary":"The input was refused","value":{"error":{"code":"invalid_request","message":"A writer refused a value: a map link on a host that is not allowed, a title that is too long, a date that does not exist, too many items in a list. The message is the writer's own sentence."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: api_scope_required, forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"api_scope_required":{"summary":"The key lacks a scope","value":{"error":{"code":"api_scope_required","message":"A read-only key called a write operation, or a key without the publish option called publish_changes."}}},"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"413":{"description":"Too large: payload_too_large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"payload_too_large":{"summary":"The request is too large","value":{"error":{"code":"payload_too_large","message":"A JSON body over 2 MB, an image over 6 MB, a batch upload over 19 MB, or an MCP message over 2 MB."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}},"delete":{"operationId":"delete_route","summary":"Delete a route (spots and places remain)","description":"Removes the route and its links. Confirm with the creator first.","tags":["routes"],"x-scope":"write","x-stability":"stable","x-since":"2026-09-17","x-mcp-tool":"delete_route","parameters":[{"name":"routeId","in":"path","required":true,"description":"Id of the route.","schema":{"type":"string","x-sceniq-id":"routes"},"example":"kx7z2x4c6v8b0n2m4q6w8e0r2t4y6v8j"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"const":true,"description":"Always true: the write went through."},"routeId":{"type":"string","x-sceniq-id":"routes","description":"The route's id."},"deleted":{"const":true,"description":"Always true: the row is gone."}},"required":["ok","routeId","deleted"],"additionalProperties":false},"examples":{"delete_a_route_the_creator_dropped_its_spots_and_places_stay":{"summary":"Delete a route the creator dropped (its spots and places stay)","value":{"ok":true,"routeId":"kx7z2x4c6v8b0n2m4q6w8e0r2t4y6v8j","deleted":true}}}}}},"400":{"description":"Invalid request: invalid_argument, invalid_request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}},"invalid_request":{"summary":"The input was refused","value":{"error":{"code":"invalid_request","message":"A writer refused a value: a map link on a host that is not allowed, a title that is too long, a date that does not exist, too many items in a list. The message is the writer's own sentence."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: api_scope_required, forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"api_scope_required":{"summary":"The key lacks a scope","value":{"error":{"code":"api_scope_required","message":"A read-only key called a write operation, or a key without the publish option called publish_changes."}}},"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"413":{"description":"Too large: payload_too_large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"payload_too_large":{"summary":"The request is too large","value":{"error":{"code":"payload_too_large","message":"A JSON body over 2 MB, an image over 6 MB, a batch upload over 19 MB, or an MCP message over 2 MB."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}}},"/routes/{routeId}/spots":{"put":{"operationId":"set_route_spots","summary":"Replace the ordered spots a route passes","description":"Full replacement: [{ spotKey, order, quickest?, role? }]. quickest marks the fastest approach to that spot. role optional marks a walk from the spot that is not the way in (the Inariyama loop above the gates): it shows as Walks from here and never sets the spot's Accessibility.","tags":["routes"],"x-scope":"write","x-stability":"stable","x-since":"2026-09-17","x-mcp-tool":"set_route_spots","parameters":[{"name":"routeId","in":"path","required":true,"description":"Id of the route.","schema":{"type":"string","x-sceniq-id":"routes"},"example":"kx7f2h8j4k0k6z2x8c4v0b6n2m8q4w0e"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"spots":{"type":"array","items":{"type":"object","properties":{"spotKey":{"type":"string","description":"A spot of this guide (spotKey from list_spots), listed once."},"order":{"type":"number","description":"The spot's position on the route (ascending, any number)."},"quickest":{"type":"boolean","description":"true marks this route as the fastest approach to that spot."},"role":{"enum":["required","optional"],"description":"required (the default): the way in. optional: a walk from the spot that is not the way in; it shows as Walks from here and never sets the spot's Accessibility."}},"required":["spotKey","order"],"additionalProperties":false},"description":"Ordered [{ spotKey, order, quickest?, role?: required|optional }], at most 200."}},"required":["spots"],"additionalProperties":false},"examples":{"link_the_trail_to_the_spot_it_leads_to":{"summary":"Link the trail to the spot it leads to","value":{"spots":[{"spotKey":"01M2Z1G0Y0QG7M2V6N9R3T5W8Y","order":1024}]}},"a_walk_from_the_spot_that_is_not_the_way_in_role_optional":{"summary":"A walk from the spot that is not the way in (role optional)","value":{"spots":[{"spotKey":"01M2Z1G0Y0R2K5P8S1V4X7Z0C3","order":1024,"role":"optional"}]}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"const":true,"description":"Always true: the write went through."},"routeId":{"type":"string","x-sceniq-id":"routes","description":"The route's id."},"edges":{"type":"number","description":"How many links the list now holds."}},"required":["ok","routeId","edges"],"additionalProperties":false},"examples":{"link_the_trail_to_the_spot_it_leads_to":{"summary":"Link the trail to the spot it leads to","value":{"ok":true,"routeId":"kx7f2h8j4k0k6z2x8c4v0b6n2m8q4w0e","edges":1}},"a_walk_from_the_spot_that_is_not_the_way_in_role_optional":{"summary":"A walk from the spot that is not the way in (role optional)","value":{"ok":true,"routeId":"kx7r4t6y8v0j2p4p6a8s0d2f4g6h8j0k","edges":1}}}}}},"400":{"description":"Invalid request: invalid_argument, invalid_request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}},"invalid_request":{"summary":"The input was refused","value":{"error":{"code":"invalid_request","message":"A writer refused a value: a map link on a host that is not allowed, a title that is too long, a date that does not exist, too many items in a list. The message is the writer's own sentence."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: api_scope_required, forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"api_scope_required":{"summary":"The key lacks a scope","value":{"error":{"code":"api_scope_required","message":"A read-only key called a write operation, or a key without the publish option called publish_changes."}}},"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"413":{"description":"Too large: payload_too_large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"payload_too_large":{"summary":"The request is too large","value":{"error":{"code":"payload_too_large","message":"A JSON body over 2 MB, an image over 6 MB, a batch upload over 19 MB, or an MCP message over 2 MB."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}}},"/routes/{routeId}/facilities":{"put":{"operationId":"set_route_facilities","summary":"Replace the places a route uses","description":"Full replacement: [{ facilityId, order }].","tags":["routes"],"x-scope":"write","x-stability":"stable","x-since":"2026-09-17","x-mcp-tool":"set_route_facilities","parameters":[{"name":"routeId","in":"path","required":true,"description":"Id of the route.","schema":{"type":"string","x-sceniq-id":"routes"},"example":"kx7f2h8j4k0k6z2x8c4v0b6n2m8q4w0e"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"facilities":{"type":"array","items":{"type":"object","properties":{"facilityId":{"type":"string","x-sceniq-id":"facilities","description":"A place of this guide (from list_facilities), listed once."},"order":{"type":"number","description":"The place's position on the route (ascending, any number)."}},"required":["facilityId","order"],"additionalProperties":false},"description":"Ordered [{ facilityId, order }], at most 50."}},"required":["facilities"],"additionalProperties":false},"examples":{"link_the_trailhead_parking_to_the_trail":{"summary":"Link the trailhead parking to the trail","value":{"facilities":[{"facilityId":"km7d4f6g8h0j2k4k6z8x0c2v4b6n8m0q","order":1024}]}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"const":true,"description":"Always true: the write went through."},"routeId":{"type":"string","x-sceniq-id":"routes","description":"The route's id."},"edges":{"type":"number","description":"How many links the list now holds."}},"required":["ok","routeId","edges"],"additionalProperties":false},"examples":{"link_the_trailhead_parking_to_the_trail":{"summary":"Link the trailhead parking to the trail","value":{"ok":true,"routeId":"kx7f2h8j4k0k6z2x8c4v0b6n2m8q4w0e","edges":1}}}}}},"400":{"description":"Invalid request: invalid_argument, invalid_request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}},"invalid_request":{"summary":"The input was refused","value":{"error":{"code":"invalid_request","message":"A writer refused a value: a map link on a host that is not allowed, a title that is too long, a date that does not exist, too many items in a list. The message is the writer's own sentence."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: api_scope_required, forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"api_scope_required":{"summary":"The key lacks a scope","value":{"error":{"code":"api_scope_required","message":"A read-only key called a write operation, or a key without the publish option called publish_changes."}}},"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"413":{"description":"Too large: payload_too_large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"payload_too_large":{"summary":"The request is too large","value":{"error":{"code":"payload_too_large","message":"A JSON body over 2 MB, an image over 6 MB, a batch upload over 19 MB, or an MCP message over 2 MB."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}}},"/guides/{productId}/facilities":{"get":{"operationId":"list_facilities","summary":"Places of a guide (stays, transport, food, parking)","description":"Planning places: kind (hut = a stay, cable_car = transport, activity = tours and activities), type, operator, raw cost and opening text, website, map link, pin, links, booking, conditions, transport and tour details, status, fees, hours, the routes' links and spotKeys (spots it serves directly).","tags":["facilities"],"x-scope":"read","x-stability":"stable","x-since":"2026-09-17","x-mcp-tool":"list_facilities","parameters":[{"name":"productId","in":"path","required":true,"description":"Id of the guide (a product of type map). From list_guides or create_guide.","schema":{"type":"string","x-sceniq-id":"products"},"example":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"productId":{"type":"string","x-sceniq-id":"products","description":"The guide's id."},"facilities":{"type":"array","items":{"$ref":"#/components/schemas/Place"},"description":"Every place, by name."}},"required":["productId","facilities"],"additionalProperties":false},"examples":{"every_place_of_a_guide_by_name":{"summary":"Every place of a guide, by name","value":{"productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","facilities":[{"facilityId":"km7d4f6g8h0j2k4k6z8x0c2v4b6n8m0q","kind":"parking","type":"parking_lot","spotKeys":["01M2Z1G0Y0QG7M2V6N9R3T5W8Y"],"name":"Fairy Falls trailhead parking","operator":null,"description":"Gravel lot at the south end of the Fountain Freight Road, room for about 50 cars.","costRaw":"Included in the park entrance fee","openRaw":"Mid April to early November, with the park roads","website":null,"mapsUrl":"https://maps.apple.com/?ll=44.5156,-110.8326&q=Fairy%20Falls%20Trailhead","extraProps":[],"lat":44.5156,"lon":-110.8326,"osmId":null,"googlePlaceId":null,"country":"US","timeZone":"America/Denver","links":[],"bookingRequired":false,"bookingUrl":null,"extraKinds":[],"insideId":null,"needsParentTicket":false,"conditions":null,"costUnit":null,"parking":{"fillsBy":"09:30 in July and August","rule":"Day use only. No overnight parking."},"transport":null,"activity":null,"gatewayTown":null,"status":null,"fees":[],"schedule":null,"sources":[],"reviewNotes":null,"factsCheckedOn":"2026-09-20","reviewBy":null,"createdAt":1789895640000,"updatedAt":1790586840000},{"facilityId":"km73j9h5g1f7d3s9a5p1p7j3v9y5t1r7","kind":"hut","type":"hotel","spotKeys":["01M2Z1G0Y0QG7M2V6N9R3T5W8Y"],"name":"Old Faithful Inn","operator":"Yellowstone National Park Lodges","description":"The 1904 log lodge next to Old Faithful, 15 minutes by car from the Fairy Falls trailhead. Old House rooms sell out first.","costRaw":"From 190 USD a night, Old House room with a shared bath (summer 2026)","openRaw":"Early May to early October","website":"https://www.yellowstonenationalparklodges.com/lodging/summer-lodges/old-faithful-inn/","mapsUrl":"https://maps.apple.com/?ll=44.4598,-110.8311&q=Old%20Faithful%20Inn","extraProps":[],"lat":44.4598,"lon":-110.8311,"osmId":null,"googlePlaceId":null,"country":"US","timeZone":"America/Denver","links":[{"kind":"booking","label":"Book a room","url":"https://www.yellowstonenationalparklodges.com/lodging/summer-lodges/old-faithful-inn/"},{"kind":"official","label":"Old Faithful area (NPS)","url":"https://www.nps.gov/yell/planyourvisit/exploreoldfaithful.htm"}],"bookingRequired":true,"bookingUrl":"https://www.yellowstonenationalparklodges.com/lodging/summer-lodges/old-faithful-inn/","extraKinds":[],"insideId":null,"needsParentTicket":false,"conditions":null,"costUnit":"per_night","parking":null,"transport":null,"activity":null,"gatewayTown":null,"status":null,"fees":[],"schedule":{"hours":[{"closed":true,"note":"Closed in winter"},{"from":"05-08","to":"10-04","note":"Open to overnight guests. Check-in from 16:00."}],"validFrom":"2026-05-08","validUntil":"2026-10-04","sourceUrl":"https://www.yellowstonenationalparklodges.com/lodging/summer-lodges/old-faithful-inn/","checkedOn":"2026-09-20"},"sources":[{"url":"https://www.yellowstonenationalparklodges.com/lodging/summer-lodges/old-faithful-inn/","kind":"page","capturedOn":"2026-09-20","supports":["costRaw","openRaw","schedule"]}],"reviewNotes":null,"factsCheckedOn":"2026-09-20","reviewBy":"2027-03-01","createdAt":1789895640000,"updatedAt":1790586840000}]}}}}}},"400":{"description":"Invalid request: invalid_argument","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}},"post":{"operationId":"create_facility","summary":"Add a place: a stay, transport, tour, food or parking","description":"costRaw and openRaw stay the creator's own words (180 USD a night, June to October); they are never parsed. website is optional and may be http (accepted with a warning); a place with only a map link is fine. mapsUrl is an allowlisted map link; give lat and lon too so the apps can map the place and show its distance to the spot (a text search link can open a namesake). Link it to routes with set_route_facilities, to spots with spotKeys. The response carries warnings that did not stop the write.","tags":["facilities"],"x-scope":"write","x-stability":"stable","x-since":"2026-09-17","x-mcp-tool":"create_facility","parameters":[{"name":"productId","in":"path","required":true,"description":"Id of the guide (a product of type map). From list_guides or create_guide.","schema":{"type":"string","x-sceniq-id":"products"},"example":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"enum":["hut","cable_car","activity","food","parking"],"description":"hut (a stay), cable_car (transport), activity (tours and activities), food (food and drink) or parking."},"name":{"type":"string","description":"Name of the place. Cannot be empty."},"activity":{"anyOf":[{"$ref":"#/components/schemas/ActivityInfo"},{"type":"null"}],"description":"Tours and activities (kind activity), null clears: { meetingPoint?, meetingLat?, meetingLon?, durationMin?, departures?, requiredToSee? (the only way to see the spot), authorizedBy?, authorizedByUrl? }."},"bookingRequired":{"type":"boolean","description":"true shows Booking required."},"bookingUrl":{"type":"string","description":"The page to book on (http or https)."},"conditions":{"anyOf":[{"$ref":"#/components/schemas/PlaceConditions"},{"type":"null"}],"description":"null clears: { minAge?, guestsOnly?, swimmersOnly?, luggageKg?, soldAsPackage?, cashOnly? }, shown as chips."},"costRaw":{"type":"string","description":"Price as the creator states it, e.g. 180 USD a night or 92 CHF half board; never parsed (costUnit says what it counts). Empty string clears."},"costUnit":{"anyOf":[{"enum":["per_person","per_night","per_person_night","per_room","per_vehicle","per_trip","per_hour","per_day"]},{"type":"null"}],"description":"What costRaw counts: per_person, per_night, per_person_night, per_room, per_vehicle, per_trip, per_hour, per_day. null clears."},"country":{"type":"string","description":"ISO 3166-1 alpha-2 code (AR, BR): places on two sides of a border read right."},"description":{"type":"string","description":"The place in the creator's words. Empty string clears."},"extraKinds":{"type":"array","items":{"enum":["hut","cable_car","activity","food","parking"]},"description":"Further roles of the same place (a hut that is also a restaurant): [hut|cable_car|activity|food|parking]. It then shows under each."},"extraProps":{"type":"array","items":{"$ref":"#/components/schemas/ExtraProp"},"description":"Free label and value rows shown on the card, full replacement ([] clears), at most 24: [{ label (at most 60 characters), value (at most 500) }]. A row with both sides empty is dropped, a half-empty one refused."},"factsCheckedOn":{"type":"string","description":"The day the facts were last checked against their sources (YYYY-MM-DD). Empty string clears."},"fees":{"type":"array","items":{"$ref":"#/components/schemas/Fee"},"description":"Fees and tickets, full replacement ([] clears), at most 30: [{ label, amount? (major units, e.g. 40 or 12.5; needs currency), currency? (EUR), free?, seeOfficial? (a price left to the official page on purpose), per?: person|vehicle|night|group|entry|day|hour, audience?: all|adult|child|foreign|domestic|resident|student|senior, paidWhere?: online|on_site|in_tour, payment?: cash_only|card_only|cash_or_card, note?, validFrom?, validUntil?, sourceUrl?, checkedOn? }]. Buyers see the amount with an as-of date; readiness flags rows past validUntil or unchecked for a year."},"gatewayTown":{"type":"string","description":"The town the place sits in when it is far from the spot on purpose (Ushuaia for an Antarctic cruise); no distance is shown then. Empty string clears."},"googlePlaceId":{"type":"string","description":"Google place id the pin came from, as a reference."},"insideId":{"anyOf":[{"type":"string","x-sceniq-id":"facilities"},{"type":"null"}],"description":"facilityId of the place this one sits inside (a restaurant inside a lodge); one level only. null clears."},"lat":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"The place's own latitude. With lon, the apps show it on the map and compute its distance to the spot; null clears."},"links":{"type":"array","items":{"$ref":"#/components/schemas/GuideLink"},"description":"Links with a purpose, full replacement ([] clears), at most 12: [{ kind: official|website|tickets|booking|status|timetable|tide|listing|social|authority|app|other, label?, url? (http or https; http is accepted with a warning), value? (a channel that is not a URL, e.g. WeChat mini program: Li River boats), note? }]. Each needs a url or a value."},"lon":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"The place's own longitude."},"mapsUrl":{"type":"string","description":"Map link: https on Google Maps, Apple Maps, Swisstopo, OpenStreetMap or SchweizMobil, or a geo: URI. Give lat and lon too. Empty string clears."},"needsParentTicket":{"type":"boolean","description":"true when entering needs the parent place's ticket."},"openRaw":{"type":"string","description":"Season or hours as text, never parsed (schedule holds structured hours). Empty string clears."},"operator":{"type":"string","description":"Who runs it. Empty string clears."},"osmId":{"type":"string","description":"OpenStreetMap reference the pin came from: node/123, way/456 or relation/789."},"parking":{"anyOf":[{"$ref":"#/components/schemas/ParkingInfo"},{"type":"null"}],"description":"Parking places, null clears: { fillsBy? (10:00), rule? (the only legal pullout) }."},"reviewBy":{"type":"string","description":"The day the facts need a new check (YYYY-MM-DD), e.g. when a season, fare or timetable runs out. get_guide_readiness and get_publish_status warn once it has passed. Empty string clears."},"reviewNotes":{"type":"string","description":"Notes for the creator's review (why a value was chosen, what could not be verified). Never shown to buyers; get_guide_readiness lists them. Empty string clears."},"schedule":{"anyOf":[{"$ref":"#/components/schemas/Schedule"},{"type":"null"}],"description":"Structured opening hours, null clears; the free-text hours stay the fallback: { hours?: [{ from? (MM-DD), to? (MM-DD, may wrap over the new year), weekdays? [1-7], closed?, open? (HH:MM or sunrise|sunset), close? (HH:MM or sunrise|sunset), openOffsetMin?, closeOffsetMin? (minutes around a sun anchor, -60 = an hour before), lastEntry? (HH:MM), leaveBy? (HH:MM), note? }], specialDays?: [{ date? or rule? (first Sunday of the month), closed?, open?, close?, note? }], slots?: { first, last, everyMin, cap?, note? }, validFrom?, validUntil?, sourceUrl?, checkedOn?, note? }. The last matching band wins, so list the year-round band first and exceptions after it. The apps show today's hours in the spot's time zone."},"sources":{"type":"array","items":{"$ref":"#/components/schemas/SourceRef"},"description":"Research evidence for reviewers, never shown to buyers; full replacement, at most 40: [{ url? or title?, kind?: page|api|archive|document|other, capturedOn?, note?, supports? (which facts it backs, e.g. fees, arrival.operating, lat/lon), conflict? (true when it disagrees with another source on those facts) }]."},"spotKeys":{"type":"array","items":{"type":"string"},"description":"spotKeys of the spots it serves directly (a hotel near a viewpoint), in order and each once, full replacement ([] clears), at most 200. Archived spots are allowed."},"status":{"anyOf":[{"$ref":"#/components/schemas/StatusNotice"},{"type":"null"}],"description":"Closure or works notice, null clears: { state: open|partly_closed|closed|reopening, note?, since?, until? (the day the state is expected to end; buyers stop seeing the notice after it), sourceUrl?, checkedOn? }. reopening with until means reopens on that day."},"transport":{"anyOf":[{"$ref":"#/components/schemas/TransportInfo"},{"type":"null"}],"description":"Transport places, null clears: { stops?: [{ name, lat?, lon?, registerId? (NSR or GTFS stop id), note? }], serviceDays? [1-7], timetableUrl?, timetableValidFrom?, timetableValidUntil?, verifyBeforeTravel? }."},"type":{"type":"string","description":"Optional sub-type. Stays: hotel, guesthouse, hostel, hut, campsite, rental, liveaboard, pontoon. Transport: cable_car, chairlift, funicular, cog_railway, train, bus, ferry, shuttle, flight, helicopter, tram, metro, taxi, bike_rental, jeep, elevator, toboggan, hub. Tours and activities: guided_tour, boat_tour, balloon, scenic_flight, jeep_safari, gear_rental. Food: restaurant, cafe, bar, bakery, grocery, market, picnic_site. Parking: parking_lot, parking_garage, street, campervan. A place without one reads as its kind's default (hut, cable_car, guided_tour, restaurant or parking_lot); empty string clears."},"website":{"type":"string","description":"Link to the official site (https, or http with a warning). Empty string clears."}},"required":["kind","name"],"additionalProperties":false},"examples":{"add_a_stay_near_a_spot_with_its_pin_booking_link_season_and_sources":{"summary":"Add a stay near a spot, with its pin, booking link, season and sources","value":{"kind":"hut","type":"hotel","name":"Old Faithful Inn","operator":"Yellowstone National Park Lodges","description":"The 1904 log lodge next to Old Faithful, 15 minutes by car from the Fairy Falls trailhead. Old House rooms sell out first.","costRaw":"From 190 USD a night, Old House room with a shared bath (summer 2026)","costUnit":"per_night","openRaw":"Early May to early October","website":"https://www.yellowstonenationalparklodges.com/lodging/summer-lodges/old-faithful-inn/","mapsUrl":"https://maps.apple.com/?ll=44.4598,-110.8311&q=Old%20Faithful%20Inn","lat":44.4598,"lon":-110.8311,"country":"US","spotKeys":["01M2Z1G0Y0QG7M2V6N9R3T5W8Y"],"bookingRequired":true,"bookingUrl":"https://www.yellowstonenationalparklodges.com/lodging/summer-lodges/old-faithful-inn/","links":[{"kind":"booking","label":"Book a room","url":"https://www.yellowstonenationalparklodges.com/lodging/summer-lodges/old-faithful-inn/"},{"kind":"official","label":"Old Faithful area (NPS)","url":"https://www.nps.gov/yell/planyourvisit/exploreoldfaithful.htm"}],"schedule":{"hours":[{"closed":true,"note":"Closed in winter"},{"from":"05-08","to":"10-04","note":"Open to overnight guests. Check-in from 16:00."}],"validFrom":"2026-05-08","validUntil":"2026-10-04","sourceUrl":"https://www.yellowstonenationalparklodges.com/lodging/summer-lodges/old-faithful-inn/","checkedOn":"2026-09-20"},"sources":[{"url":"https://www.yellowstonenationalparklodges.com/lodging/summer-lodges/old-faithful-inn/","kind":"page","capturedOn":"2026-09-20","supports":["costRaw","openRaw","schedule"]}],"factsCheckedOn":"2026-09-20","reviewBy":"2027-03-01"}},"an_expedition_ship_that_leaves_from_a_gateway_town_far_from_the_spot":{"summary":"An expedition ship that leaves from a gateway town far from the spot","value":{"kind":"activity","type":"boat_tour","extraKinds":["hut"],"name":"Expedition cruise from Ushuaia","description":"Ten nights on a small expedition ship: two days across the Drake Passage, then landings on the Peninsula. Most itineraries sail the Lemaire Channel when the ice allows.","costRaw":"From 9,800 USD per person in a twin cabin (2026-27 season)","costUnit":"per_person","openRaw":"Departures from early November to mid March","mapsUrl":"https://www.google.com/maps/search/?api=1&query=-54.8069,-68.302","lat":-54.8069,"lon":-68.302,"country":"AR","gatewayTown":"Ushuaia","spotKeys":["01KXFYF4Y0A3C6E9G2J5K8N1Q4"],"bookingRequired":true,"conditions":{"soldAsPackage":true,"minAge":8},"activity":{"meetingPoint":"Port of Ushuaia, main pier","meetingLat":-54.8069,"meetingLon":-68.302,"durationMin":14400,"departures":"About every ten days from early November to mid March","requiredToSee":true,"authorizedBy":"IAATO member operators","authorizedByUrl":"https://iaato.org/"},"fees":[{"label":"Twin cabin, 10 nights","amount":9800,"currency":"USD","per":"person","paidWhere":"online","note":"The lowest fare of the season; suites and single cabins cost more.","validFrom":"2026-11-01","validUntil":"2027-03-20","checkedOn":"2026-09-20"}],"links":[{"kind":"authority","label":"IAATO member operators","url":"https://iaato.org/"}],"sources":[{"title":"Operator brochure, 2026-27 season (PDF from the creator)","kind":"document","capturedOn":"2026-09-18","supports":["costRaw","fees","activity"]}],"reviewNotes":"Fares are from one operator's brochure; ask the creator which operator the guide should name.","factsCheckedOn":"2026-09-20","reviewBy":"2027-03-20"}}}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlaceWrite"},"examples":{"add_a_stay_near_a_spot_with_its_pin_booking_link_season_and_sources":{"summary":"Add a stay near a spot, with its pin, booking link, season and sources","value":{"facilityId":"km73j9h5g1f7d3s9a5p1p7j3v9y5t1r7","kind":"hut","type":"hotel","spotKeys":["01M2Z1G0Y0QG7M2V6N9R3T5W8Y"],"name":"Old Faithful Inn","operator":"Yellowstone National Park Lodges","description":"The 1904 log lodge next to Old Faithful, 15 minutes by car from the Fairy Falls trailhead. Old House rooms sell out first.","costRaw":"From 190 USD a night, Old House room with a shared bath (summer 2026)","openRaw":"Early May to early October","website":"https://www.yellowstonenationalparklodges.com/lodging/summer-lodges/old-faithful-inn/","mapsUrl":"https://maps.apple.com/?ll=44.4598,-110.8311&q=Old%20Faithful%20Inn","extraProps":[],"lat":44.4598,"lon":-110.8311,"osmId":null,"googlePlaceId":null,"country":"US","timeZone":"America/Denver","links":[{"kind":"booking","label":"Book a room","url":"https://www.yellowstonenationalparklodges.com/lodging/summer-lodges/old-faithful-inn/"},{"kind":"official","label":"Old Faithful area (NPS)","url":"https://www.nps.gov/yell/planyourvisit/exploreoldfaithful.htm"}],"bookingRequired":true,"bookingUrl":"https://www.yellowstonenationalparklodges.com/lodging/summer-lodges/old-faithful-inn/","extraKinds":[],"insideId":null,"needsParentTicket":false,"conditions":null,"costUnit":"per_night","parking":null,"transport":null,"activity":null,"gatewayTown":null,"status":null,"fees":[],"schedule":{"hours":[{"closed":true,"note":"Closed in winter"},{"from":"05-08","to":"10-04","note":"Open to overnight guests. Check-in from 16:00."}],"validFrom":"2026-05-08","validUntil":"2026-10-04","sourceUrl":"https://www.yellowstonenationalparklodges.com/lodging/summer-lodges/old-faithful-inn/","checkedOn":"2026-09-20"},"sources":[{"url":"https://www.yellowstonenationalparklodges.com/lodging/summer-lodges/old-faithful-inn/","kind":"page","capturedOn":"2026-09-20","supports":["costRaw","openRaw","schedule"]}],"reviewNotes":null,"factsCheckedOn":"2026-09-20","reviewBy":"2027-03-01","createdAt":1789895640000,"updatedAt":1789895640000}},"an_expedition_ship_that_leaves_from_a_gateway_town_far_from_the_spot":{"summary":"An expedition ship that leaves from a gateway town far from the spot","value":{"facilityId":"km7s8v2w4y6a8c0e2g4j6k8m0p2q4s6v","kind":"activity","type":"boat_tour","spotKeys":["01KXFYF4Y0A3C6E9G2J5K8N1Q4"],"name":"Expedition cruise from Ushuaia","operator":null,"description":"Ten nights on a small expedition ship: two days across the Drake Passage, then landings on the Peninsula. Most itineraries sail the Lemaire Channel when the ice allows.","costRaw":"From 9,800 USD per person in a twin cabin (2026-27 season)","openRaw":"Departures from early November to mid March","website":null,"mapsUrl":"https://www.google.com/maps/search/?api=1&query=-54.8069,-68.302","extraProps":[],"lat":-54.8069,"lon":-68.302,"osmId":null,"googlePlaceId":null,"country":"AR","timeZone":"America/Argentina/Ushuaia","links":[{"kind":"authority","label":"IAATO member operators","url":"https://iaato.org/"}],"bookingRequired":true,"bookingUrl":null,"extraKinds":["hut"],"insideId":null,"needsParentTicket":false,"conditions":{"soldAsPackage":true,"minAge":8},"costUnit":"per_person","parking":null,"transport":null,"activity":{"meetingPoint":"Port of Ushuaia, main pier","meetingLat":-54.8069,"meetingLon":-68.302,"durationMin":14400,"departures":"About every ten days from early November to mid March","requiredToSee":true,"authorizedBy":"IAATO member operators","authorizedByUrl":"https://iaato.org/"},"gatewayTown":"Ushuaia","status":null,"fees":[{"label":"Twin cabin, 10 nights","amount":9800,"currency":"USD","per":"person","paidWhere":"online","note":"The lowest fare of the season; suites and single cabins cost more.","validFrom":"2026-11-01","validUntil":"2027-03-20","checkedOn":"2026-09-20"}],"schedule":null,"sources":[{"title":"Operator brochure, 2026-27 season (PDF from the creator)","kind":"document","capturedOn":"2026-09-18","supports":["costRaw","fees","activity"]}],"reviewNotes":"Fares are from one operator's brochure; ask the creator which operator the guide should name.","factsCheckedOn":"2026-09-20","reviewBy":"2027-03-20","createdAt":1790673240000,"updatedAt":1790673240000}}}}}},"400":{"description":"Invalid request: invalid_argument, invalid_request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}},"invalid_request":{"summary":"The input was refused","value":{"error":{"code":"invalid_request","message":"A writer refused a value: a map link on a host that is not allowed, a title that is too long, a date that does not exist, too many items in a list. The message is the writer's own sentence."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: api_scope_required, forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"api_scope_required":{"summary":"The key lacks a scope","value":{"error":{"code":"api_scope_required","message":"A read-only key called a write operation, or a key without the publish option called publish_changes."}}},"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"413":{"description":"Too large: payload_too_large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"payload_too_large":{"summary":"The request is too large","value":{"error":{"code":"payload_too_large","message":"A JSON body over 2 MB, an image over 6 MB, a batch upload over 19 MB, or an MCP message over 2 MB."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}}},"/facilities/{facilityId}":{"patch":{"operationId":"update_facility","summary":"Edit a place","description":"Only sent fields change; empty strings clear (type \"\" falls back to the kind's default), null clears an object or the pin, lists are full replacements; spotKeys replaces the whole list.","tags":["facilities"],"x-scope":"write","x-stability":"stable","x-since":"2026-09-17","x-mcp-tool":"update_facility","parameters":[{"name":"facilityId","in":"path","required":true,"description":"Id of the facility (from list_facilities).","schema":{"type":"string","x-sceniq-id":"facilities"},"example":"km7d4f6g8h0j2k4k6z8x0c2v4b6n8m0q"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"activity":{"anyOf":[{"$ref":"#/components/schemas/ActivityInfo"},{"type":"null"}],"description":"Tours and activities (kind activity), null clears: { meetingPoint?, meetingLat?, meetingLon?, durationMin?, departures?, requiredToSee? (the only way to see the spot), authorizedBy?, authorizedByUrl? }."},"bookingRequired":{"type":"boolean","description":"true shows Booking required."},"bookingUrl":{"type":"string","description":"The page to book on (http or https)."},"conditions":{"anyOf":[{"$ref":"#/components/schemas/PlaceConditions"},{"type":"null"}],"description":"null clears: { minAge?, guestsOnly?, swimmersOnly?, luggageKg?, soldAsPackage?, cashOnly? }, shown as chips."},"costRaw":{"type":"string","description":"Price as the creator states it, e.g. 180 USD a night or 92 CHF half board; never parsed (costUnit says what it counts). Empty string clears."},"costUnit":{"anyOf":[{"enum":["per_person","per_night","per_person_night","per_room","per_vehicle","per_trip","per_hour","per_day"]},{"type":"null"}],"description":"What costRaw counts: per_person, per_night, per_person_night, per_room, per_vehicle, per_trip, per_hour, per_day. null clears."},"country":{"type":"string","description":"ISO 3166-1 alpha-2 code (AR, BR): places on two sides of a border read right."},"description":{"type":"string","description":"The place in the creator's words. Empty string clears."},"extraKinds":{"type":"array","items":{"enum":["hut","cable_car","activity","food","parking"]},"description":"Further roles of the same place (a hut that is also a restaurant): [hut|cable_car|activity|food|parking]. It then shows under each."},"extraProps":{"type":"array","items":{"$ref":"#/components/schemas/ExtraProp"},"description":"Free label and value rows shown on the card, full replacement ([] clears), at most 24: [{ label (at most 60 characters), value (at most 500) }]. A row with both sides empty is dropped, a half-empty one refused."},"factsCheckedOn":{"type":"string","description":"The day the facts were last checked against their sources (YYYY-MM-DD). Empty string clears."},"fees":{"type":"array","items":{"$ref":"#/components/schemas/Fee"},"description":"Fees and tickets, full replacement ([] clears), at most 30: [{ label, amount? (major units, e.g. 40 or 12.5; needs currency), currency? (EUR), free?, seeOfficial? (a price left to the official page on purpose), per?: person|vehicle|night|group|entry|day|hour, audience?: all|adult|child|foreign|domestic|resident|student|senior, paidWhere?: online|on_site|in_tour, payment?: cash_only|card_only|cash_or_card, note?, validFrom?, validUntil?, sourceUrl?, checkedOn? }]. Buyers see the amount with an as-of date; readiness flags rows past validUntil or unchecked for a year."},"gatewayTown":{"type":"string","description":"The town the place sits in when it is far from the spot on purpose (Ushuaia for an Antarctic cruise); no distance is shown then. Empty string clears."},"googlePlaceId":{"type":"string","description":"Google place id the pin came from, as a reference."},"insideId":{"anyOf":[{"type":"string","x-sceniq-id":"facilities"},{"type":"null"}],"description":"facilityId of the place this one sits inside (a restaurant inside a lodge); one level only. null clears."},"kind":{"enum":["hut","cable_car","activity","food","parking"],"description":"Moves the place to another kind: hut (a stay), cable_car (transport), activity (tours and activities), food or parking. A type the new kind does not have is dropped."},"lat":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"The place's own latitude. With lon, the apps show it on the map and compute its distance to the spot; null clears."},"links":{"type":"array","items":{"$ref":"#/components/schemas/GuideLink"},"description":"Links with a purpose, full replacement ([] clears), at most 12: [{ kind: official|website|tickets|booking|status|timetable|tide|listing|social|authority|app|other, label?, url? (http or https; http is accepted with a warning), value? (a channel that is not a URL, e.g. WeChat mini program: Li River boats), note? }]. Each needs a url or a value."},"lon":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"The place's own longitude."},"mapsUrl":{"type":"string","description":"Map link: https on Google Maps, Apple Maps, Swisstopo, OpenStreetMap or SchweizMobil, or a geo: URI. Give lat and lon too. Empty string clears."},"name":{"type":"string","description":"Name of the place. Cannot be empty."},"needsParentTicket":{"type":"boolean","description":"true when entering needs the parent place's ticket."},"openRaw":{"type":"string","description":"Season or hours as text, never parsed (schedule holds structured hours). Empty string clears."},"operator":{"type":"string","description":"Who runs it. Empty string clears."},"osmId":{"type":"string","description":"OpenStreetMap reference the pin came from: node/123, way/456 or relation/789."},"parking":{"anyOf":[{"$ref":"#/components/schemas/ParkingInfo"},{"type":"null"}],"description":"Parking places, null clears: { fillsBy? (10:00), rule? (the only legal pullout) }."},"reviewBy":{"type":"string","description":"The day the facts need a new check (YYYY-MM-DD), e.g. when a season, fare or timetable runs out. get_guide_readiness and get_publish_status warn once it has passed. Empty string clears."},"reviewNotes":{"type":"string","description":"Notes for the creator's review (why a value was chosen, what could not be verified). Never shown to buyers; get_guide_readiness lists them. Empty string clears."},"schedule":{"anyOf":[{"$ref":"#/components/schemas/Schedule"},{"type":"null"}],"description":"Structured opening hours, null clears; the free-text hours stay the fallback: { hours?: [{ from? (MM-DD), to? (MM-DD, may wrap over the new year), weekdays? [1-7], closed?, open? (HH:MM or sunrise|sunset), close? (HH:MM or sunrise|sunset), openOffsetMin?, closeOffsetMin? (minutes around a sun anchor, -60 = an hour before), lastEntry? (HH:MM), leaveBy? (HH:MM), note? }], specialDays?: [{ date? or rule? (first Sunday of the month), closed?, open?, close?, note? }], slots?: { first, last, everyMin, cap?, note? }, validFrom?, validUntil?, sourceUrl?, checkedOn?, note? }. The last matching band wins, so list the year-round band first and exceptions after it. The apps show today's hours in the spot's time zone."},"sources":{"type":"array","items":{"$ref":"#/components/schemas/SourceRef"},"description":"Research evidence for reviewers, never shown to buyers; full replacement, at most 40: [{ url? or title?, kind?: page|api|archive|document|other, capturedOn?, note?, supports? (which facts it backs, e.g. fees, arrival.operating, lat/lon), conflict? (true when it disagrees with another source on those facts) }]."},"spotKeys":{"type":"array","items":{"type":"string"},"description":"spotKeys of the spots it serves directly (a hotel near a viewpoint), in order and each once, full replacement ([] clears), at most 200. Archived spots are allowed."},"status":{"anyOf":[{"$ref":"#/components/schemas/StatusNotice"},{"type":"null"}],"description":"Closure or works notice, null clears: { state: open|partly_closed|closed|reopening, note?, since?, until? (the day the state is expected to end; buyers stop seeing the notice after it), sourceUrl?, checkedOn? }. reopening with until means reopens on that day."},"transport":{"anyOf":[{"$ref":"#/components/schemas/TransportInfo"},{"type":"null"}],"description":"Transport places, null clears: { stops?: [{ name, lat?, lon?, registerId? (NSR or GTFS stop id), note? }], serviceDays? [1-7], timetableUrl?, timetableValidFrom?, timetableValidUntil?, verifyBeforeTravel? }."},"type":{"type":"string","description":"Optional sub-type. Stays: hotel, guesthouse, hostel, hut, campsite, rental, liveaboard, pontoon. Transport: cable_car, chairlift, funicular, cog_railway, train, bus, ferry, shuttle, flight, helicopter, tram, metro, taxi, bike_rental, jeep, elevator, toboggan, hub. Tours and activities: guided_tour, boat_tour, balloon, scenic_flight, jeep_safari, gear_rental. Food: restaurant, cafe, bar, bakery, grocery, market, picnic_site. Parking: parking_lot, parking_garage, street, campervan. A place without one reads as its kind's default (hut, cable_car, guided_tour, restaurant or parking_lot); empty string clears."},"website":{"type":"string","description":"Link to the official site (https, or http with a warning). Empty string clears."}},"additionalProperties":false},"examples":{"post_a_notice_and_record_when_the_lot_fills":{"summary":"Post a notice and record when the lot fills","value":{"status":{"state":"partly_closed","note":"Half the lot is fenced off for repaving until 10 October.","since":"2026-09-28","until":"2026-10-10","sourceUrl":"https://www.nps.gov/yell/planyourvisit/conditions.htm","checkedOn":"2026-09-29"},"parking":{"fillsBy":"08:30 while the repaving lasts","rule":"Day use only. No overnight parking."},"factsCheckedOn":"2026-09-29"}},"clear_fields_null_clears_an_object_an_empty_string_clears_text":{"summary":"Clear fields: null clears an object, an empty string clears text","value":{"status":null,"reviewNotes":""}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"const":true,"description":"Always true: the write went through."},"facilityId":{"type":"string","x-sceniq-id":"facilities","description":"The place's id."},"warnings":{"type":"array","items":{"type":"string"},"description":"Notes about things the write accepted but you should look at (a plain http link). Present only when there are any."}},"required":["ok","facilityId"],"additionalProperties":false},"examples":{"post_a_notice_and_record_when_the_lot_fills":{"summary":"Post a notice and record when the lot fills","value":{"ok":true,"facilityId":"km7d4f6g8h0j2k4k6z8x0c2v4b6n8m0q"}},"clear_fields_null_clears_an_object_an_empty_string_clears_text":{"summary":"Clear fields: null clears an object, an empty string clears text","value":{"ok":true,"facilityId":"km73j9h5g1f7d3s9a5p1p7j3v9y5t1r7"}}}}}},"400":{"description":"Invalid request: invalid_argument, invalid_request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}},"invalid_request":{"summary":"The input was refused","value":{"error":{"code":"invalid_request","message":"A writer refused a value: a map link on a host that is not allowed, a title that is too long, a date that does not exist, too many items in a list. The message is the writer's own sentence."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: api_scope_required, forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"api_scope_required":{"summary":"The key lacks a scope","value":{"error":{"code":"api_scope_required","message":"A read-only key called a write operation, or a key without the publish option called publish_changes."}}},"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"413":{"description":"Too large: payload_too_large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"payload_too_large":{"summary":"The request is too large","value":{"error":{"code":"payload_too_large","message":"A JSON body over 2 MB, an image over 6 MB, a batch upload over 19 MB, or an MCP message over 2 MB."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}},"delete":{"operationId":"delete_facility","summary":"Delete a place","description":"Removes the place with its route and spot links. Confirm with the creator first.","tags":["facilities"],"x-scope":"write","x-stability":"stable","x-since":"2026-09-17","x-mcp-tool":"delete_facility","parameters":[{"name":"facilityId","in":"path","required":true,"description":"Id of the facility.","schema":{"type":"string","x-sceniq-id":"facilities"},"example":"km7h3j5k7k9z1x3c5v7b9n1m3q5w7e9r"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"const":true,"description":"Always true: the write went through."},"facilityId":{"type":"string","x-sceniq-id":"facilities","description":"The place's id."},"deleted":{"const":true,"description":"Always true: the row is gone."}},"required":["ok","facilityId","deleted"],"additionalProperties":false},"examples":{"delete_a_place_the_creator_dropped_its_route_and_spot_links_go_with_it":{"summary":"Delete a place the creator dropped (its route and spot links go with it)","value":{"ok":true,"facilityId":"km7h3j5k7k9z1x3c5v7b9n1m3q5w7e9r","deleted":true}}}}}},"400":{"description":"Invalid request: invalid_argument, invalid_request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}},"invalid_request":{"summary":"The input was refused","value":{"error":{"code":"invalid_request","message":"A writer refused a value: a map link on a host that is not allowed, a title that is too long, a date that does not exist, too many items in a list. The message is the writer's own sentence."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: api_scope_required, forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"api_scope_required":{"summary":"The key lacks a scope","value":{"error":{"code":"api_scope_required","message":"A read-only key called a write operation, or a key without the publish option called publish_changes."}}},"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"413":{"description":"Too large: payload_too_large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"payload_too_large":{"summary":"The request is too large","value":{"error":{"code":"payload_too_large","message":"A JSON body over 2 MB, an image over 6 MB, a batch upload over 19 MB, or an MCP message over 2 MB."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}}},"/guides/{productId}/media":{"get":{"operationId":"list_media","summary":"Photos of a guide with their owner rows","description":"Every photo with URL, thumbUrl (the ~640 px variant; made on the server for API uploads, usually within seconds), caption, alt, credit, dimensions, focal point, provenance and review fields, and the row it belongs to (spot, product, collection or listing). Uploading is a plain HTTP request, see whoami.endpoints.upload (one file) or whoami.endpoints.uploadBatch (up to 10 with a JSON manifest) and the authoring guide.","tags":["media"],"x-scope":"read","x-stability":"stable","x-since":"2026-09-17","x-mcp-tool":"list_media","parameters":[{"name":"productId","in":"path","required":true,"description":"Id of the guide (a product of type map). From list_guides or create_guide.","schema":{"type":"string","x-sceniq-id":"products"},"example":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2"},{"name":"marketingOnly","in":"query","required":false,"description":"true returns only product- and listing-owned photos (sales page candidates).","schema":{"type":"boolean"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"productId":{"type":"string","x-sceniq-id":"products","description":"The guide's id."},"media":{"type":"array","items":{"$ref":"#/components/schemas/Photo"},"description":"Every photo of the guide in order."}},"required":["productId","media"],"additionalProperties":false},"examples":{"every_photo_of_a_guide_with_its_owner_row":{"summary":"Every photo of a guide, with its owner row","value":{"productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","media":[{"mediaId":"kg71s3d5f7g9h1j3k5k7z9x1c3v5b7n9","url":"https://quiet-heron-512.convex.cloud/api/storage/grand-prismatic-overlook.webp","thumbUrl":"https://quiet-heron-512.convex.cloud/api/storage/grand-prismatic-overlook-640.webp","ownerType":"spot","ownerId":"k1709e2vj4sk8q6x0d3m5r7t9w1y3b5c","caption":"Grand Prismatic Spring from the overlook, mid morning","alt":"A deep blue pool ringed with orange and yellow, steam drifting over the boardwalk below","credit":"Mara Lindgren","width":2048,"height":1365,"order":1024,"focalX":0.52,"focalY":0.46,"sourcePageUrl":null,"licence":null,"creditUrl":null,"shows":{"kind":"spot"},"takenAt":{"lat":44.5199,"lon":-110.8406,"precision":"gps"},"locationVerifiedBy":"geotag","capturedOn":"2026-09-14","reviewNotes":null},{"mediaId":"kg7q8w6e4r2t0y8v6j4p2p0a8s6d4f2g","url":"https://quiet-heron-512.convex.cloud/api/storage/hero-grand-prismatic.webp","thumbUrl":"https://quiet-heron-512.convex.cloud/api/storage/hero-grand-prismatic-640.webp","ownerType":"product","ownerId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","caption":"Grand Prismatic Spring from the overlook","alt":"A deep blue pool ringed with orange and yellow, steam drifting over the boardwalk below","credit":"Mara Lindgren","width":2048,"height":1365,"order":1024,"focalX":0.52,"focalY":0.46,"sourcePageUrl":null,"licence":null,"creditUrl":null,"shows":{"kind":"spot"},"takenAt":null,"locationVerifiedBy":null,"capturedOn":null,"reviewNotes":null},{"mediaId":"kg7p2p4j6v8y0t2r4e6w8q0a2s4d6f8g","url":"https://quiet-heron-512.convex.cloud/api/storage/grand-prismatic-aerial.webp","thumbUrl":"https://quiet-heron-512.convex.cloud/api/storage/grand-prismatic-aerial-640.webp","ownerType":"spot","ownerId":"k1709e2vj4sk8q6x0d3m5r7t9w1y3b5c","caption":"Grand Prismatic Spring and Midway Geyser Basin from above","alt":"An aerial view of a deep blue hot spring ringed in orange and yellow, with steam, the boardwalk and the Firehole River beside it","credit":"Brocken Inaglory","width":2048,"height":1365,"order":2048,"focalX":null,"focalY":null,"sourcePageUrl":"https://commons.wikimedia.org/wiki/File:Grand_Prismatic_Spring_and_Midway_Geyser_Basin_from_above.jpg","licence":"CC BY-SA 3.0","creditUrl":"http://commons.wikimedia.org/wiki/User:Brocken_Inaglory","shows":{"kind":"spot","label":"From above"},"takenAt":null,"locationVerifiedBy":"photographer_caption","capturedOn":"2008-07-30","reviewNotes":null}]}},"only_the_photos_a_sales_page_may_use_product_and_listing_photos":{"summary":"Only the photos a sales page may use (product and listing photos)","value":{"productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","media":[{"mediaId":"kg7q8w6e4r2t0y8v6j4p2p0a8s6d4f2g","url":"https://quiet-heron-512.convex.cloud/api/storage/hero-grand-prismatic.webp","thumbUrl":"https://quiet-heron-512.convex.cloud/api/storage/hero-grand-prismatic-640.webp","ownerType":"product","ownerId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","caption":"Grand Prismatic Spring from the overlook","alt":"A deep blue pool ringed with orange and yellow, steam drifting over the boardwalk below","credit":"Mara Lindgren","width":2048,"height":1365,"order":1024,"focalX":0.52,"focalY":0.46,"sourcePageUrl":null,"licence":null,"creditUrl":null,"shows":{"kind":"spot"},"takenAt":null,"locationVerifiedBy":null,"capturedOn":null,"reviewNotes":null},{"mediaId":"kg7b4n6m8q0w2e4r6t8y0v2j4p6p8a0s","url":"https://quiet-heron-512.convex.cloud/api/storage/guide-map-yellowstone.webp","thumbUrl":"https://quiet-heron-512.convex.cloud/api/storage/guide-map-yellowstone-640.webp","ownerType":"listing","ownerId":"kr7w1e3r5t7y9v1j3p5p7a9s1d3f5g7h","caption":"The guide's map of Yellowstone in the Sceniq app","alt":"A phone showing a map of Yellowstone with pins for viewpoints, trailheads and parking","credit":null,"width":1638,"height":2048,"order":1024,"focalX":null,"focalY":null,"sourcePageUrl":null,"licence":null,"creditUrl":null,"shows":null,"takenAt":null,"locationVerifiedBy":null,"capturedOn":null,"reviewNotes":null},{"mediaId":"kg7t5y7v9j1p3p5a7s9d1f3g5h7j9k1k","url":"https://quiet-heron-512.convex.cloud/api/storage/tunnel-view-first-light.webp","thumbUrl":"https://quiet-heron-512.convex.cloud/api/storage/tunnel-view-first-light-640.webp","ownerType":"product","ownerId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","caption":"Tunnel View at first light","alt":"Yosemite Valley at sunrise: El Capitan on the left, Half Dome ahead, Bridalveil Fall on the right","credit":"Mara Lindgren","width":2048,"height":1365,"order":2048,"focalX":null,"focalY":null,"sourcePageUrl":null,"licence":null,"creditUrl":null,"shows":{"kind":"view_from_spot"},"takenAt":null,"locationVerifiedBy":null,"capturedOn":null,"reviewNotes":null}]}}}}}},"400":{"description":"Invalid request: invalid_argument","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}}},"/media/{mediaId}":{"patch":{"operationId":"update_media","summary":"Set a photo's caption, alt, credit, focal point or provenance","description":"Credits render as Photo: Name and are a hard platform rule: never drop or invent one; ask the creator whose photo it is. Only sent fields change; null clears a metadata field (alt, focal point, licence, shows, takenAt and the rest), while caption and credit take text and store it as sent. The response carries warnings that did not stop the write.","tags":["media"],"x-scope":"write","x-stability":"stable","x-since":"2026-09-17","x-mcp-tool":"update_media","parameters":[{"name":"mediaId","in":"path","required":true,"description":"Id of the media row.","schema":{"type":"string","x-sceniq-id":"media"},"example":"kg71s3d5f7g9h1j3k5k7z9x1c3v5b7n9"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"alt":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Alt text: what the photo shows, for screen readers. The caption is the fallback."},"caption":{"type":"string","description":"Caption text, shown under the photo. Stored as sent."},"capturedOn":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Capture date (YYYY-MM-DD). Upload reads it from the file's metadata before stripping it when present."},"credit":{"type":"string","description":"Photographer credit, rendered as Photo: Name. Stored as sent."},"creditUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The photographer's profile page."},"focalX":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Focal point 0 (left) to 1 (right); with focalY the apps keep it in frame when they crop to a card."},"focalY":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Focal point 0 (top) to 1 (bottom)."},"licence":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Licence name (Unsplash License, CC BY 4.0)."},"locationVerifiedBy":{"anyOf":[{"enum":["geotag","landmark","photographer_caption","creator","other"]},{"type":"null"}],"description":"How the location was confirmed: geotag, landmark, photographer_caption, creator or other."},"reviewNotes":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Notes for the creator's review (why a value was chosen, what could not be verified). Never shown to buyers; get_guide_readiness lists them. Empty string clears."},"shows":{"anyOf":[{"$ref":"#/components/schemas/PhotoShows"},{"type":"null"}],"description":"What the photo shows, null clears: { kind: spot|view_from_spot|nearby|approach|detail|other, label? }."},"sourcePageUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The page the photo was licensed from (an Unsplash photo page). Not the image file."},"takenAt":{"anyOf":[{"$ref":"#/components/schemas/PhotoTakenAt"},{"type":"null"}],"description":"Where it was taken, null clears: { lat, lon, precision: gps|geocode|none }. A gps fix more than 2 km from the pin is flagged by readiness."}},"additionalProperties":false},"examples":{"add_alt_text_a_focal_point_and_where_the_photo_was_taken":{"summary":"Add alt text, a focal point and where the photo was taken","value":{"alt":"A deep blue pool ringed with orange and yellow, steam drifting over the boardwalk below","focalX":0.52,"focalY":0.46,"shows":{"kind":"spot"},"takenAt":{"lat":44.5199,"lon":-110.8406,"precision":"gps"},"locationVerifiedBy":"geotag"}},"record_a_licensed_photo_s_credit_and_licence_an_http_link_comes_back_as_a_warning":{"summary":"Record a licensed photo's credit and licence (an http link comes back as a warning)","value":{"credit":"Brocken Inaglory","licence":"CC BY-SA 3.0","sourcePageUrl":"https://commons.wikimedia.org/wiki/File:Grand_Prismatic_Spring_and_Midway_Geyser_Basin_from_above.jpg","creditUrl":"http://commons.wikimedia.org/wiki/User:Brocken_Inaglory"}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"const":true,"description":"Always true: the write went through."},"mediaId":{"type":"string","x-sceniq-id":"media","description":"The photo's id."},"warnings":{"type":"array","items":{"type":"string"},"description":"Notes about things the write accepted but you should look at (a plain http link). Present only when there are any."}},"required":["ok","mediaId"],"additionalProperties":false},"examples":{"add_alt_text_a_focal_point_and_where_the_photo_was_taken":{"summary":"Add alt text, a focal point and where the photo was taken","value":{"ok":true,"mediaId":"kg71s3d5f7g9h1j3k5k7z9x1c3v5b7n9"}},"record_a_licensed_photo_s_credit_and_licence_an_http_link_comes_back_as_a_warning":{"summary":"Record a licensed photo's credit and licence (an http link comes back as a warning)","value":{"ok":true,"mediaId":"kg7p2p4j6v8y0t2r4e6w8q0a2s4d6f8g","warnings":["creditUrl uses http, not https: http://commons.wikimedia.org/wiki/User:Brocken_Inaglory"]}}}}}},"400":{"description":"Invalid request: invalid_argument, invalid_request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}},"invalid_request":{"summary":"The input was refused","value":{"error":{"code":"invalid_request","message":"A writer refused a value: a map link on a host that is not allowed, a title that is too long, a date that does not exist, too many items in a list. The message is the writer's own sentence."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: api_scope_required, forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"api_scope_required":{"summary":"The key lacks a scope","value":{"error":{"code":"api_scope_required","message":"A read-only key called a write operation, or a key without the publish option called publish_changes."}}},"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"413":{"description":"Too large: payload_too_large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"payload_too_large":{"summary":"The request is too large","value":{"error":{"code":"payload_too_large","message":"A JSON body over 2 MB, an image over 6 MB, a batch upload over 19 MB, or an MCP message over 2 MB."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}},"delete":{"operationId":"delete_media","summary":"Remove a photo","description":"Deletes the media row (sales page slides referencing it stop resolving). Confirm with the creator first.","tags":["media"],"x-scope":"write","x-stability":"stable","x-since":"2026-09-17","x-mcp-tool":"delete_media","parameters":[{"name":"mediaId","in":"path","required":true,"description":"Id of the media row.","schema":{"type":"string","x-sceniq-id":"media"},"example":"kg7d8f0g2h4j6k8k0z2x4c6v8b0n2m4q"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"const":true,"description":"Always true: the write went through."},"mediaId":{"type":"string","x-sceniq-id":"media","description":"The photo's id."},"deleted":{"const":true,"description":"Always true: the row is gone."}},"required":["ok","mediaId","deleted"],"additionalProperties":false},"examples":{"remove_a_photo_uploaded_twice":{"summary":"Remove a photo uploaded twice","value":{"ok":true,"mediaId":"kg7d8f0g2h4j6k8k0z2x4c6v8b0n2m4q","deleted":true}}}}}},"400":{"description":"Invalid request: invalid_argument, invalid_request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}},"invalid_request":{"summary":"The input was refused","value":{"error":{"code":"invalid_request","message":"A writer refused a value: a map link on a host that is not allowed, a title that is too long, a date that does not exist, too many items in a list. The message is the writer's own sentence."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: api_scope_required, forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"api_scope_required":{"summary":"The key lacks a scope","value":{"error":{"code":"api_scope_required","message":"A read-only key called a write operation, or a key without the publish option called publish_changes."}}},"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"413":{"description":"Too large: payload_too_large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"payload_too_large":{"summary":"The request is too large","value":{"error":{"code":"payload_too_large","message":"A JSON body over 2 MB, an image over 6 MB, a batch upload over 19 MB, or an MCP message over 2 MB."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}}},"/media/{mediaId}/order":{"put":{"operationId":"reorder_media","summary":"Move a photo within its owner's gallery","description":"Fractional order key; pick a value between the neighbours you read from list_media.","tags":["media"],"x-scope":"write","x-stability":"stable","x-since":"2026-09-17","x-mcp-tool":"reorder_media","parameters":[{"name":"mediaId","in":"path","required":true,"description":"Id of the media row.","schema":{"type":"string","x-sceniq-id":"media"},"example":"kg7p2p4j6v8y0t2r4e6w8q0a2s4d6f8g"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"order":{"type":"number","description":"New fractional order value."}},"required":["order"],"additionalProperties":false},"examples":{"move_a_photo_in_front_of_the_first_one_order_1024":{"summary":"Move a photo in front of the first one (order 1024)","value":{"order":512}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"const":true,"description":"Always true: the write went through."},"mediaId":{"type":"string","x-sceniq-id":"media","description":"The photo's id."},"order":{"type":"number","description":"The new order value."}},"required":["ok","mediaId","order"],"additionalProperties":false},"examples":{"move_a_photo_in_front_of_the_first_one_order_1024":{"summary":"Move a photo in front of the first one (order 1024)","value":{"ok":true,"mediaId":"kg7p2p4j6v8y0t2r4e6w8q0a2s4d6f8g","order":512}}}}}},"400":{"description":"Invalid request: invalid_argument, invalid_request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}},"invalid_request":{"summary":"The input was refused","value":{"error":{"code":"invalid_request","message":"A writer refused a value: a map link on a host that is not allowed, a title that is too long, a date that does not exist, too many items in a list. The message is the writer's own sentence."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: api_scope_required, forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"api_scope_required":{"summary":"The key lacks a scope","value":{"error":{"code":"api_scope_required","message":"A read-only key called a write operation, or a key without the publish option called publish_changes."}}},"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"413":{"description":"Too large: payload_too_large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"payload_too_large":{"summary":"The request is too large","value":{"error":{"code":"payload_too_large","message":"A JSON body over 2 MB, an image over 6 MB, a batch upload over 19 MB, or an MCP message over 2 MB."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}}},"/guides/{productId}/links":{"get":{"operationId":"get_link_report","summary":"Health of every link buyers can open in the guide","description":"Every creator link (spot links and map pills, place websites and booking pages, route sources, status, fee and schedule sources, area links) with its last check: ok, redirected (to another domain), unverifiable (the site turns scripts away: a bot wall, 403, 429 or a timeout, which is not an error), broken (no DNS, refused, 404), suspicious (parked, suspended, gambling spam or a soft 404), tls (certificate problem) or unchecked, and where it is used. New links are checked shortly after a write; every link is re-checked about weekly.","tags":["links"],"x-scope":"read","x-stability":"beta","x-since":"2026-09-30","x-mcp-tool":"get_link_report","parameters":[{"name":"productId","in":"path","required":true,"description":"Id of the guide (a product of type map). From list_guides or create_guide.","schema":{"type":"string","x-sceniq-id":"products"},"example":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkReport"},"examples":{"link_health_of_a_guide_one_redirect_to_look_at_one_site_that_walls_off_scripts":{"summary":"Link health of a guide: one redirect to look at, one site that walls off scripts","value":{"productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","total":6,"counts":{"redirected":1,"unverifiable":1,"ok":4},"flagged":1,"links":[{"url":"https://www.yellowstonenationalparklodges.com/lodging/summer-lodges/old-faithful-inn/","state":"redirected","reason":"other_domain","httpStatus":200,"finalUrl":"https://www.xanterra.com/","checkedAt":1790655240000,"lastOkAt":1790586840000,"manualOkOn":null,"manualNote":null,"flagged":true,"usedBy":[{"kind":"place","id":"km73j9h5g1f7d3s9a5p1p7j3v9y5t1r7","name":"Old Faithful Inn","field":"bookingUrl"},{"kind":"place","id":"km73j9h5g1f7d3s9a5p1p7j3v9y5t1r7","name":"Old Faithful Inn","field":"links"}]},{"url":"https://www.recreation.gov/timed-entry/10086745","state":"unverifiable","reason":"bot_wall","httpStatus":403,"finalUrl":null,"checkedAt":1790655240000,"lastOkAt":null,"manualOkOn":"2026-09-29","manualNote":"Opened in a browser: the 2026 timed entry page loads.","flagged":false,"usedBy":[{"kind":"spot","id":"k17bc3xz8h6f4d2s0q9w7e5r3t1y2v4j","name":"Tunnel View","field":"arrival"}]},{"url":"https://www.nps.gov/yell/planyourvisit/conditions.htm","state":"ok","reason":"ok","httpStatus":200,"finalUrl":null,"checkedAt":1790655240000,"lastOkAt":1790655240000,"manualOkOn":null,"manualNote":null,"flagged":false,"usedBy":[{"kind":"spot","id":"k1709e2vj4sk8q6x0d3m5r7t9w1y3b5c","name":"Grand Prismatic Spring","field":"links"},{"kind":"route","id":"kx7f2h8j4k0k6z2x8c4v0b6n2m8q4w0e","name":"Fairy Falls trail to the Grand Prismatic overlook","field":"season"}]},{"url":"https://www.nps.gov/yell/planyourvisit/fees.htm","state":"ok","reason":"ok","httpStatus":200,"finalUrl":null,"checkedAt":1790655240000,"lastOkAt":1790655240000,"manualOkOn":null,"manualNote":null,"flagged":false,"usedBy":[{"kind":"spot","id":"k1709e2vj4sk8q6x0d3m5r7t9w1y3b5c","name":"Grand Prismatic Spring","field":"fees"}]},{"url":"https://www.nps.gov/places/000/grand-prismatic-spring.htm","state":"ok","reason":"ok","httpStatus":200,"finalUrl":null,"checkedAt":1790655240000,"lastOkAt":1790655240000,"manualOkOn":null,"manualNote":null,"flagged":false,"usedBy":[{"kind":"spot","id":"k1709e2vj4sk8q6x0d3m5r7t9w1y3b5c","name":"Grand Prismatic Spring","field":"links"},{"kind":"route","id":"kx7f2h8j4k0k6z2x8c4v0b6n2m8q4w0e","name":"Fairy Falls trail to the Grand Prismatic overlook","field":"sources"}]},{"url":"https://www.yellowstonenationalparklodges.com/lodging/summer-lodges/old-faithful-inn/","state":"ok","reason":"ok","httpStatus":200,"finalUrl":null,"checkedAt":1790655240000,"lastOkAt":1790655240000,"manualOkOn":null,"manualNote":null,"flagged":false,"usedBy":[{"kind":"place","id":"km73j9h5g1f7d3s9a5p1p7j3v9y5t1r7","name":"Old Faithful Inn","field":"website"},{"kind":"place","id":"km73j9h5g1f7d3s9a5p1p7j3v9y5t1r7","name":"Old Faithful Inn","field":"schedule"}]}]}}}}}},"400":{"description":"Invalid request: invalid_argument","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}}},"/guides/{productId}/links/check":{"post":{"operationId":"check_links","summary":"Check the guide's links now","description":"Queues checks for unchecked links and links not checked in a day, or exactly the urls you pass (at most 40), or every link with all true. Results land within a minute or two; read them with get_link_report. Limited to 12 calls per guide per hour.","tags":["links"],"x-scope":"write","x-stability":"beta","x-since":"2026-09-30","x-mcp-tool":"check_links","parameters":[{"name":"productId","in":"path","required":true,"description":"Id of the guide (a product of type map). From list_guides or create_guide.","schema":{"type":"string","x-sceniq-id":"products"},"example":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"all":{"type":"boolean","description":"true re-checks every link, not only unchecked and stale ones."},"urls":{"type":"array","items":{"type":"string"},"description":"Check exactly these links of the guide (at most 40)."}},"additionalProperties":false},"examples":{"re_check_one_link_now_for_example_after_the_site_fixed_a_redirect":{"summary":"Re-check one link now, for example after the site fixed a redirect","value":{"urls":["https://www.yellowstonenationalparklodges.com/lodging/summer-lodges/old-faithful-inn/"]}},"re_check_every_link_checked_recently_or_not":{"summary":"Re-check every link, checked recently or not","value":{"all":true}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"queued":{"type":"number","description":"Links queued for a check."},"total":{"type":"number","description":"Links of the guide."},"productId":{"type":"string","x-sceniq-id":"products","description":"The guide's id."},"nextStep":{"type":"string","description":"What to do next."}},"required":["queued","total","productId","nextStep"],"additionalProperties":false},"examples":{"check_the_links_that_are_new_or_were_not_checked_in_the_last_day":{"summary":"Check the links that are new or were not checked in the last day","value":{"queued":2,"total":8,"productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","nextStep":"Checks are running; read get_link_report in a minute or two."}},"re_check_one_link_now_for_example_after_the_site_fixed_a_redirect":{"summary":"Re-check one link now, for example after the site fixed a redirect","value":{"queued":1,"total":8,"productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","nextStep":"Checks are running; read get_link_report in a minute or two."}},"re_check_every_link_checked_recently_or_not":{"summary":"Re-check every link, checked recently or not","value":{"queued":8,"total":8,"productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","nextStep":"Checks are running; read get_link_report in a minute or two."}}}}}},"400":{"description":"Invalid request: invalid_argument, invalid_request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}},"invalid_request":{"summary":"The input was refused","value":{"error":{"code":"invalid_request","message":"A writer refused a value: a map link on a host that is not allowed, a title that is too long, a date that does not exist, too many items in a list. The message is the writer's own sentence."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: api_scope_required, forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"api_scope_required":{"summary":"The key lacks a scope","value":{"error":{"code":"api_scope_required","message":"A read-only key called a write operation, or a key without the publish option called publish_changes."}}},"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"413":{"description":"Too large: payload_too_large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"payload_too_large":{"summary":"The request is too large","value":{"error":{"code":"payload_too_large","message":"A JSON body over 2 MB, an image over 6 MB, a batch upload over 19 MB, or an MCP message over 2 MB."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}}},"/guides/{productId}/links/verified":{"put":{"operationId":"set_link_verified","summary":"Record that a link was confirmed by hand","description":"For an official site that walls off scripts: after the creator (or you, in a real browser) confirmed the page, record it so readiness stops flagging the link for 180 days. clear true removes the record.","tags":["links"],"x-scope":"write","x-stability":"beta","x-since":"2026-09-30","x-mcp-tool":"set_link_verified","parameters":[{"name":"productId","in":"path","required":true,"description":"Id of the guide (a product of type map). From list_guides or create_guide.","schema":{"type":"string","x-sceniq-id":"products"},"example":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","description":"The link exactly as stored in the guide."},"clear":{"type":"boolean","description":"true removes the manual confirmation."},"note":{"type":"string","description":"How it was confirmed (opened in a browser, Wayback copy of 2026-09-12)."},"verifiedOn":{"type":"string","description":"The day it was confirmed (YYYY-MM-DD, default today)."}},"required":["url"],"additionalProperties":false},"examples":{"record_that_an_official_page_which_walls_off_scripts_was_confirmed_in_a_browser":{"summary":"Record that an official page which walls off scripts was confirmed in a browser","value":{"url":"https://www.recreation.gov/timed-entry/10086745","verifiedOn":"2026-09-29","note":"Opened in a browser: the 2026 timed entry page loads."}},"remove_the_manual_confirmation":{"summary":"Remove the manual confirmation","value":{"url":"https://www.recreation.gov/timed-entry/10086745","clear":true}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"const":true,"description":"Always true: the write went through."},"productId":{"type":"string","x-sceniq-id":"products","description":"The guide's id."},"url":{"type":"string","description":"The link."},"manualOkOn":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The recorded confirmation day, or null after clear."}},"required":["ok","productId","url","manualOkOn"],"additionalProperties":false},"examples":{"record_that_an_official_page_which_walls_off_scripts_was_confirmed_in_a_browser":{"summary":"Record that an official page which walls off scripts was confirmed in a browser","value":{"ok":true,"productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","url":"https://www.recreation.gov/timed-entry/10086745","manualOkOn":"2026-09-29"}},"remove_the_manual_confirmation":{"summary":"Remove the manual confirmation","value":{"ok":true,"productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","url":"https://www.recreation.gov/timed-entry/10086745","manualOkOn":null}}}}}},"400":{"description":"Invalid request: invalid_argument, invalid_request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}},"invalid_request":{"summary":"The input was refused","value":{"error":{"code":"invalid_request","message":"A writer refused a value: a map link on a host that is not allowed, a title that is too long, a date that does not exist, too many items in a list. The message is the writer's own sentence."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: api_scope_required, forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"api_scope_required":{"summary":"The key lacks a scope","value":{"error":{"code":"api_scope_required","message":"A read-only key called a write operation, or a key without the publish option called publish_changes."}}},"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"413":{"description":"Too large: payload_too_large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"payload_too_large":{"summary":"The request is too large","value":{"error":{"code":"payload_too_large","message":"A JSON body over 2 MB, an image over 6 MB, a batch upload over 19 MB, or an MCP message over 2 MB."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}}},"/guides/{productId}/sales-page":{"get":{"operationId":"get_sales_page","summary":"The default sales page: draft, published state, media map","description":"Returns the listing row (draftConfig is what you edit; publishedConfig is live) and the media rows it may reference. null listing means no draft exists yet; save_sales_page_draft creates it.","tags":["sales-page"],"x-scope":"read","x-stability":"stable","x-since":"2026-09-17","x-mcp-tool":"get_sales_page","parameters":[{"name":"productId","in":"path","required":true,"description":"Id of the guide (a product of type map). From list_guides or create_guide.","schema":{"type":"string","x-sceniq-id":"products"},"example":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SalesPage"},"examples":{"a_live_sales_page_with_a_newer_draft_and_the_photos_it_may_use":{"summary":"A live sales page with a newer draft, and the photos it may use","value":{"productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","listing":{"listingId":"kr7w1e3r5t7y9v1j3p5p7a9s1d3f5g7h","status":"published","baseLanguage":"en","draftConfig":{"hero":{"carousel":[{"mediaId":"kg7q8w6e4r2t0y8v6j4p2p0a8s6d4f2g","order":1024},{"mediaId":"kg7t5y7v9j1p3p5a7s9d1f3g5h7j9k1k","caption":"Tunnel View, Yosemite, at first light","order":2048},{"mediaId":"kg7b4n6m8q0w2e4r6t8y0v2j4p6p8a0s","order":3072}],"title":"American West: Parks at First Light","headline":"Twelve viewpoints across Yellowstone and Yosemite, timed for the light and the crowds.","kicker":"A map guide by Mara Lindgren","bullets":[{"text":"Twelve viewpoints in Yellowstone and Yosemite, each with an exact pin","order":1},{"text":"The best hour for every view, and when the crowds arrive","order":2},{"text":"Trailheads, parking and the time each lot fills","order":3},{"text":"Fees, opening hours and closures checked in September 2026","order":4}]},"pitch":{"enabled":true,"title":"Built for the hour you are there","description":"Every spot says when to arrive, where to park and how long the walk takes, so the good light finds you at the viewpoint, not in the parking lot.","imageAspect":"4:5","boxes":[{"mediaId":"kg7b4n6m8q0w2e4r6t8y0v2j4p6p8a0s","title":"One map for both parks","description":"Pins for every viewpoint, trailhead and lot, in the Sceniq app and in your browser.","order":1},{"mediaId":"kg7q8w6e4r2t0y8v6j4p2p0a8s6d4f2g","title":"Timed for the light","description":"Grand Prismatic mid morning once the steam lifts, Tunnel View at first light.","order":2},{"title":"Parking that works","description":"Which lot to use, when it fills, and where to go when it does.","order":3}]},"reviews":{"enabled":true,"source":"product","heading":"What buyers say"},"gallery":{"enabled":false,"slides":[]},"aboutCreator":{"enabled":true},"buyForm":{"ctaLabel":"Get the guide","reassuranceText":"One payment. Open it in the Sceniq app or in your browser.","imageMediaId":"kg7t5y7v9j1p3p5a7s9d1f3g5h7j9k1k"},"faq":{"enabled":true,"title":"Common questions","items":[{"question":"Do I need a car?","answer":"Yes. Every spot lists where to park, how early the lot fills and how long the walk is from there.","order":1},{"question":"Does the guide work without signal?","answer":"Download it in the Sceniq app before you go. The map, the spots and the photos then open without signal, which most of these viewpoints do not have.","order":2},{"question":"When should I go?","answer":"Late May to September for both parks. Each spot lists its best months and the hour it looks its best.","order":3}]}},"draftUpdatedAt":1790586840000,"publishedConfig":{"hero":{"carousel":[{"mediaId":"kg7q8w6e4r2t0y8v6j4p2p0a8s6d4f2g","order":1024},{"mediaId":"kg7t5y7v9j1p3p5a7s9d1f3g5h7j9k1k","caption":"Tunnel View, Yosemite, at first light","order":2048},{"mediaId":"kg7b4n6m8q0w2e4r6t8y0v2j4p6p8a0s","order":3072}],"title":"American West: Parks at First Light","headline":"Twelve viewpoints across Yellowstone and Yosemite, timed for the light and the crowds.","kicker":"A map guide by Mara Lindgren","bullets":[{"text":"Twelve viewpoints in Yellowstone and Yosemite, each with an exact pin","order":1},{"text":"The best hour for every view, and when the crowds arrive","order":2},{"text":"Trailheads, parking and the time each lot fills","order":3}]},"pitch":{"enabled":true,"title":"Built for the hour you are there","description":"Every spot says when to arrive, where to park and how long the walk takes, so the good light finds you at the viewpoint, not in the parking lot.","imageAspect":"4:5","boxes":[{"mediaId":"kg7b4n6m8q0w2e4r6t8y0v2j4p6p8a0s","title":"One map for both parks","description":"Pins for every viewpoint, trailhead and lot, in the Sceniq app and in your browser.","order":1},{"mediaId":"kg7q8w6e4r2t0y8v6j4p2p0a8s6d4f2g","title":"Timed for the light","description":"Grand Prismatic mid morning once the steam lifts, Tunnel View at first light.","order":2},{"title":"Parking that works","description":"Which lot to use, when it fills, and where to go when it does.","order":3}]},"reviews":{"enabled":true,"source":"product","heading":"What buyers say"},"gallery":{"enabled":false,"slides":[]},"aboutCreator":{"enabled":true},"buyForm":{"ctaLabel":"Get the guide","reassuranceText":"One payment. Open it in the Sceniq app or in your browser.","imageMediaId":"kg7t5y7v9j1p3p5a7s9d1f3g5h7j9k1k"},"faq":{"enabled":false,"items":[]}},"publishedAt":1790241240000,"publishedConfigVersion":3,"locales":[],"metaTitle":"American West: Parks at First Light: a map guide by Mara Lindgren","metaDescription":"Twelve viewpoints across Yellowstone and Yosemite with the best hour, the parking and the fees for each.","updatedAt":1790586840000},"mediaMap":{"kg7q8w6e4r2t0y8v6j4p2p0a8s6d4f2g":{"id":"kg7q8w6e4r2t0y8v6j4p2p0a8s6d4f2g","url":"https://quiet-heron-512.convex.cloud/api/storage/hero-grand-prismatic.webp","caption":"Grand Prismatic Spring from the overlook","credit":"Mara Lindgren","width":2048,"height":1365,"order":1024},"kg7b4n6m8q0w2e4r6t8y0v2j4p6p8a0s":{"id":"kg7b4n6m8q0w2e4r6t8y0v2j4p6p8a0s","url":"https://quiet-heron-512.convex.cloud/api/storage/guide-map-yellowstone.webp","caption":"The guide's map of Yellowstone in the Sceniq app","width":1638,"height":2048,"order":1024},"kg7t5y7v9j1p3p5a7s9d1f3g5h7j9k1k":{"id":"kg7t5y7v9j1p3p5a7s9d1f3g5h7j9k1k","url":"https://quiet-heron-512.convex.cloud/api/storage/tunnel-view-first-light.webp","caption":"Tunnel View at first light","credit":"Mara Lindgren","width":2048,"height":1365,"order":2048}},"publishing":"The creator publishes the sales page in the dashboard; save_sales_page_draft only updates the draft."}}}}}},"400":{"description":"Invalid request: invalid_argument","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}}},"/guides/{productId}/sales-page/draft":{"put":{"operationId":"save_sales_page_draft","summary":"Save the sales page draft (never publishes)","description":"Full-replacement draftConfig with the fixed sections: hero (carousel of listing/product media ids, title, 2-6 bullets), pitch boxes, reviews (custom testimonials only with the creator's real quotes), gallery, aboutCreator, buyForm, faq. Media ids must be product- or listing-owned. Copy must never promise updates. The creator publishes the sales page in the dashboard; publish_changes does not touch it.","tags":["sales-page"],"x-scope":"write","x-stability":"stable","x-since":"2026-09-17","x-mcp-tool":"save_sales_page_draft","parameters":[{"name":"productId","in":"path","required":true,"description":"Id of the guide (a product of type map). From list_guides or create_guide.","schema":{"type":"string","x-sceniq-id":"products"},"example":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"draftConfig":{"$ref":"#/components/schemas/ListingConfig","description":"The complete ListingConfig object (read get_sales_page first and edit that)."},"expectedUpdatedAt":{"type":"number","description":"Optional staleness guard: the listing updatedAt you last read."}},"required":["draftConfig"],"additionalProperties":false},"examples":{"save_the_whole_draft_guarded_against_an_edit_made_elsewhere_since_the_last_read":{"summary":"Save the whole draft, guarded against an edit made elsewhere since the last read","value":{"draftConfig":{"hero":{"carousel":[{"mediaId":"kg7q8w6e4r2t0y8v6j4p2p0a8s6d4f2g","order":1024},{"mediaId":"kg7t5y7v9j1p3p5a7s9d1f3g5h7j9k1k","caption":"Tunnel View, Yosemite, at first light","order":2048},{"mediaId":"kg7b4n6m8q0w2e4r6t8y0v2j4p6p8a0s","order":3072}],"title":"American West: Parks at First Light","headline":"Twelve viewpoints across Yellowstone and Yosemite, timed for the light and the crowds.","kicker":"A map guide by Mara Lindgren","bullets":[{"text":"Twelve viewpoints in Yellowstone and Yosemite, each with an exact pin","order":1},{"text":"The best hour for every view, and when the crowds arrive","order":2},{"text":"Trailheads, parking and the time each lot fills","order":3},{"text":"Fees, opening hours and closures checked in September 2026","order":4}]},"pitch":{"enabled":true,"title":"Built for the hour you are there","description":"Every spot says when to arrive, where to park and how long the walk takes, so the good light finds you at the viewpoint, not in the parking lot.","imageAspect":"4:5","boxes":[{"mediaId":"kg7b4n6m8q0w2e4r6t8y0v2j4p6p8a0s","title":"One map for both parks","description":"Pins for every viewpoint, trailhead and lot, in the Sceniq app and in your browser.","order":1},{"mediaId":"kg7q8w6e4r2t0y8v6j4p2p0a8s6d4f2g","title":"Timed for the light","description":"Grand Prismatic mid morning once the steam lifts, Tunnel View at first light.","order":2},{"title":"Parking that works","description":"Which lot to use, when it fills, and where to go when it does.","order":3}]},"reviews":{"enabled":true,"source":"product","heading":"What buyers say"},"gallery":{"enabled":false,"slides":[]},"aboutCreator":{"enabled":true},"buyForm":{"ctaLabel":"Get the guide","reassuranceText":"One payment. Open it in the Sceniq app or in your browser.","imageMediaId":"kg7t5y7v9j1p3p5a7s9d1f3g5h7j9k1k"},"faq":{"enabled":true,"title":"Common questions","items":[{"question":"Do I need a car?","answer":"Yes. Every spot lists where to park, how early the lot fills and how long the walk is from there.","order":1},{"question":"Does the guide work without signal?","answer":"Download it in the Sceniq app before you go. The map, the spots and the photos then open without signal, which most of these viewpoints do not have.","order":2},{"question":"When should I go?","answer":"Late May to September for both parks. Each spot lists its best months and the hour it looks its best.","order":3}]}},"expectedUpdatedAt":1790241240000}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"const":true,"description":"Always true: the write went through."},"productId":{"type":"string","x-sceniq-id":"products","description":"The guide's id."},"saved":{"const":"draft","description":"Always draft: the creator publishes the sales page."}},"required":["ok","productId","saved"],"additionalProperties":false},"examples":{"save_the_whole_draft_guarded_against_an_edit_made_elsewhere_since_the_last_read":{"summary":"Save the whole draft, guarded against an edit made elsewhere since the last read","value":{"ok":true,"productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","saved":"draft"}}}}}},"400":{"description":"Invalid request: invalid_argument, invalid_request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}},"invalid_request":{"summary":"The input was refused","value":{"error":{"code":"invalid_request","message":"A writer refused a value: a map link on a host that is not allowed, a title that is too long, a date that does not exist, too many items in a list. The message is the writer's own sentence."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: api_scope_required, forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"api_scope_required":{"summary":"The key lacks a scope","value":{"error":{"code":"api_scope_required","message":"A read-only key called a write operation, or a key without the publish option called publish_changes."}}},"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"409":{"description":"The row's state refuses it: stale_editor","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"stale_editor":{"summary":"It changed since you read it","value":{"error":{"code":"stale_editor","message":"The row changed after the expectedUpdatedAt you sent (update_chapter, save_sales_page_draft)."}}}}}}},"413":{"description":"Too large: payload_too_large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"payload_too_large":{"summary":"The request is too large","value":{"error":{"code":"payload_too_large","message":"A JSON body over 2 MB, an image over 6 MB, a batch upload over 19 MB, or an MCP message over 2 MB."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}}},"/guides/{productId}/publish":{"get":{"operationId":"get_publish_status","summary":"What buyers see, unpublished changes, and what blocks a publish","description":"Whether the guide is live, the live version and when it went live, whether the draft holds changes buyers do not see yet (and the last edit time), whether a publish is still building (pendingSince), blocking: the publish gates, the same check publish_changes enforces, and warnings that do not block (facts past their review-by date, link problems). Read it before publish_changes, and poll it afterwards until pendingSince is null and published.version went up. Any key can read it.","tags":["publishing"],"x-scope":"read","x-stability":"stable","x-since":"2026-09-29","x-mcp-tool":"get_publish_status","parameters":[{"name":"productId","in":"path","required":true,"description":"Id of the guide (a product of type map). From list_guides or create_guide.","schema":{"type":"string","x-sceniq-id":"products"},"example":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublishStatus"},"examples":{"a_live_guide_with_unpublished_changes_and_nothing_blocking_a_link_warning_does_not_block":{"summary":"A live guide with unpublished changes and nothing blocking (a link warning does not block)","value":{"productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","name":"American West: Parks at First Light","status":"published","live":true,"published":{"publishedAt":1790241240000,"version":3},"lastEditAt":1790586840000,"blocking":[],"warnings":[{"code":"link_problems","message":"1 link(s) look dead, parked or redirected; see get_link_report"}],"reviewUrl":"https://creators.sceniq.earth/products/j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","hasUnpublishedChanges":true,"pendingSince":null,"canPublishChanges":true,"nextStep":"Ready. Call publish_changes only when the creator asked you to publish."}},"polling_after_publish_changes_the_build_is_in_and_the_version_went_up":{"summary":"Polling after publish_changes: the build is in and the version went up","value":{"productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","name":"American West: Parks at First Light","status":"published","live":true,"published":{"publishedAt":1790673249000,"version":4},"lastEditAt":1790586840000,"blocking":[],"warnings":[{"code":"link_problems","message":"1 link(s) look dead, parked or redirected; see get_link_report"}],"reviewUrl":"https://creators.sceniq.earth/products/j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","hasUnpublishedChanges":false,"pendingSince":null,"canPublishChanges":false,"nextStep":"Buyers already see every change. Nothing to publish."}}}}}},"400":{"description":"Invalid request: invalid_argument","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}},"post":{"operationId":"publish_changes","summary":"Publish a live guide's draft changes to buyers","description":"Only when the creator asks you to publish, and only after get_publish_status shows unpublished changes and no blocking items. Needs a key with the publish option (403 api_scope_required otherwise). Live guides only: a draft's first publish (putting it on sale), archiving, store visibility and the sales page stay in the dashboard. Runs the same build as the dashboard's Publish changes button; buyers keep the current version until the new one is in. Returns the queued state; then poll get_publish_status until pendingSince is null and published.version went up, usually within seconds. While a publish is still building, calling it again queues nothing new (queued false). Refused with 409 no_changes when buyers already see every change, 409 not_publishable with the blocking list, 409 not_live for a guide that is not on sale.","tags":["publishing"],"x-scope":"publish","x-stability":"stable","x-since":"2026-09-29","x-mcp-tool":"publish_changes","parameters":[{"name":"productId","in":"path","required":true,"description":"Id of the guide (a product of type map). From list_guides or create_guide.","schema":{"type":"string","x-sceniq-id":"products"},"example":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublishQueued"},"examples":{"publish_the_draft_changes_the_creator_asked_for_the_build_is_queued":{"summary":"Publish the draft changes the creator asked for; the build is queued","value":{"queued":true,"productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","name":"American West: Parks at First Light","status":"published","live":true,"published":{"publishedAt":1790241240000,"version":3},"lastEditAt":1790586840000,"blocking":[],"warnings":[{"code":"link_problems","message":"1 link(s) look dead, parked or redirected; see get_link_report"}],"reviewUrl":"https://creators.sceniq.earth/products/j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","hasUnpublishedChanges":true,"pendingSince":1790673240000,"canPublishChanges":false,"nextStep":"A publish is building. Poll get_publish_status until pendingSince is null and published.version went up (usually seconds)."}},"calling_again_while_the_build_runs_queues_nothing_new":{"summary":"Calling again while the build runs queues nothing new","value":{"queued":false,"productId":"j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","name":"American West: Parks at First Light","status":"published","live":true,"published":{"publishedAt":1790241240000,"version":3},"lastEditAt":1790586840000,"blocking":[],"warnings":[{"code":"link_problems","message":"1 link(s) look dead, parked or redirected; see get_link_report"}],"reviewUrl":"https://creators.sceniq.earth/products/j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2","hasUnpublishedChanges":true,"pendingSince":1790673240000,"canPublishChanges":false,"nextStep":"A publish is building. Poll get_publish_status until pendingSince is null and published.version went up (usually seconds)."}}}}}},"400":{"description":"Invalid request: invalid_argument, invalid_request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}},"invalid_request":{"summary":"The input was refused","value":{"error":{"code":"invalid_request","message":"A writer refused a value: a map link on a host that is not allowed, a title that is too long, a date that does not exist, too many items in a list. The message is the writer's own sentence."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: api_scope_required, forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"api_scope_required":{"summary":"The key lacks a scope","value":{"error":{"code":"api_scope_required","message":"A read-only key called a write operation, or a key without the publish option called publish_changes."}}},"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"409":{"description":"The row's state refuses it: not_publishable, not_live, no_changes, agreement_outdated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_publishable":{"summary":"A publish gate is open","value":{"error":{"code":"not_publishable","message":"publish_changes while a gate is open: the agreement, no live spot, a live spot without a pin or a photo, no price. details.blocking lists each gate as { code, message }."}}},"not_live":{"summary":"The guide is not on sale","value":{"error":{"code":"not_live","message":"publish_changes on a draft or archived guide. A draft's first publish happens in the studio."}}},"no_changes":{"summary":"Nothing to publish","value":{"error":{"code":"no_changes","message":"publish_changes when buyers already see every change."}}},"agreement_outdated":{"summary":"The agreement needs accepting","value":{"error":{"code":"agreement_outdated","message":"A price change or a publish before the creator accepted the current creator agreement."}}}}}}},"413":{"description":"Too large: payload_too_large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"payload_too_large":{"summary":"The request is too large","value":{"error":{"code":"payload_too_large","message":"A JSON body over 2 MB, an image over 6 MB, a batch upload over 19 MB, or an MCP message over 2 MB."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}}},"/profile":{"get":{"operationId":"get_profile","summary":"The creator's public profile","description":"Display name, real name, bio, avatar, socials, the URL slug (read-only).","tags":["profile"],"x-scope":"read","x-stability":"stable","x-since":"2026-09-17","x-mcp-tool":"get_profile","parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Profile"},"examples":{"the_creator_s_public_profile":{"summary":"The creator's public profile","value":{"creatorId":"k97c2m4vx8r1q0d6s5t3n9p2w7y4h8b1","slug":"mara-lindgren","displayName":"Mara Lindgren","realName":null,"bio":"Landscape photographer. I plan every trip around the light and share the exact spots, times and parking so you can do the same.","email":"mara@example.com","avatarUrl":"https://quiet-heron-512.convex.cloud/api/storage/mara-lindgren-avatar.webp","socials":[{"platform":"instagram","handle":"mara.firstlight","url":"https://www.instagram.com/mara.firstlight/","followerCount":184000},{"platform":"youtube","handle":"marafirstlight","url":"https://www.youtube.com/@marafirstlight","followerCount":52300},{"platform":"tiktok","handle":"mara.firstlight","url":"https://www.tiktok.com/@mara.firstlight"}],"role":"owner"}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}},"patch":{"operationId":"update_profile","summary":"Change the display name or real name","description":"Only sent fields change; realName empty clears. The slug and the login email are read-only.","tags":["profile"],"x-scope":"write","x-stability":"stable","x-since":"2026-09-17","x-mcp-tool":"update_profile","parameters":[],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"displayName":{"type":"string","description":"Public brand name, at most 80 characters."},"realName":{"type":"string","description":"Legal name shown on the dashboard profile."}},"additionalProperties":false},"examples":{"set_the_legal_name_shown_on_the_studio_profile":{"summary":"Set the legal name shown on the studio profile","value":{"realName":"Mara Sofia Lindgren"}},"rename_the_public_brand_and_clear_the_legal_name_empty_string":{"summary":"Rename the public brand and clear the legal name (empty string)","value":{"displayName":"Mara Lindgren Photography","realName":""}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Profile"},"examples":{"set_the_legal_name_shown_on_the_studio_profile":{"summary":"Set the legal name shown on the studio profile","value":{"creatorId":"k97c2m4vx8r1q0d6s5t3n9p2w7y4h8b1","slug":"mara-lindgren","displayName":"Mara Lindgren","realName":"Mara Sofia Lindgren","bio":"Landscape photographer. I plan every trip around the light and share the exact spots, times and parking so you can do the same.","email":"mara@example.com","avatarUrl":"https://quiet-heron-512.convex.cloud/api/storage/mara-lindgren-avatar.webp","socials":[{"platform":"instagram","handle":"mara.firstlight","url":"https://www.instagram.com/mara.firstlight/","followerCount":184000},{"platform":"youtube","handle":"marafirstlight","url":"https://www.youtube.com/@marafirstlight","followerCount":52300},{"platform":"tiktok","handle":"mara.firstlight","url":"https://www.tiktok.com/@mara.firstlight"}],"role":"owner"}},"rename_the_public_brand_and_clear_the_legal_name_empty_string":{"summary":"Rename the public brand and clear the legal name (empty string)","value":{"creatorId":"k97c2m4vx8r1q0d6s5t3n9p2w7y4h8b1","slug":"mara-lindgren","displayName":"Mara Lindgren Photography","realName":null,"bio":"Landscape photographer. I plan every trip around the light and share the exact spots, times and parking so you can do the same.","email":"mara@example.com","avatarUrl":"https://quiet-heron-512.convex.cloud/api/storage/mara-lindgren-avatar.webp","socials":[{"platform":"instagram","handle":"mara.firstlight","url":"https://www.instagram.com/mara.firstlight/","followerCount":184000},{"platform":"youtube","handle":"marafirstlight","url":"https://www.youtube.com/@marafirstlight","followerCount":52300},{"platform":"tiktok","handle":"mara.firstlight","url":"https://www.tiktok.com/@mara.firstlight"}],"role":"owner"}}}}}},"400":{"description":"Invalid request: invalid_argument, invalid_request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}},"invalid_request":{"summary":"The input was refused","value":{"error":{"code":"invalid_request","message":"A writer refused a value: a map link on a host that is not allowed, a title that is too long, a date that does not exist, too many items in a list. The message is the writer's own sentence."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: api_scope_required, forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"api_scope_required":{"summary":"The key lacks a scope","value":{"error":{"code":"api_scope_required","message":"A read-only key called a write operation, or a key without the publish option called publish_changes."}}},"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"413":{"description":"Too large: payload_too_large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"payload_too_large":{"summary":"The request is too large","value":{"error":{"code":"payload_too_large","message":"A JSON body over 2 MB, an image over 6 MB, a batch upload over 19 MB, or an MCP message over 2 MB."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}}},"/profile/socials":{"put":{"operationId":"set_profile_socials","summary":"Replace the social links on the profile","description":"Full replacement: [{ platform: instagram|tiktok|youtube, handle, url, followerCount? }], at most 6.","tags":["profile"],"x-scope":"write","x-stability":"stable","x-since":"2026-09-17","x-mcp-tool":"set_profile_socials","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"socials":{"type":"array","items":{"$ref":"#/components/schemas/SocialLink"},"description":"The complete list of social links."}},"required":["socials"],"additionalProperties":false},"examples":{"replace_the_social_links_the_whole_list":{"summary":"Replace the social links (the whole list)","value":{"socials":[{"platform":"instagram","handle":"mara.firstlight","url":"https://www.instagram.com/mara.firstlight/","followerCount":184000},{"platform":"youtube","handle":"marafirstlight","url":"https://www.youtube.com/@marafirstlight","followerCount":52300},{"platform":"tiktok","handle":"mara.firstlight","url":"https://www.tiktok.com/@mara.firstlight"}]}},"keep_only_instagram_every_link_left_out_is_removed":{"summary":"Keep only Instagram: every link left out is removed","value":{"socials":[{"platform":"instagram","handle":"mara.firstlight","url":"https://www.instagram.com/mara.firstlight/","followerCount":184000}]}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Profile"},"examples":{"replace_the_social_links_the_whole_list":{"summary":"Replace the social links (the whole list)","value":{"creatorId":"k97c2m4vx8r1q0d6s5t3n9p2w7y4h8b1","slug":"mara-lindgren","displayName":"Mara Lindgren","realName":null,"bio":"Landscape photographer. I plan every trip around the light and share the exact spots, times and parking so you can do the same.","email":"mara@example.com","avatarUrl":"https://quiet-heron-512.convex.cloud/api/storage/mara-lindgren-avatar.webp","socials":[{"platform":"instagram","handle":"mara.firstlight","url":"https://www.instagram.com/mara.firstlight/","followerCount":184000},{"platform":"youtube","handle":"marafirstlight","url":"https://www.youtube.com/@marafirstlight","followerCount":52300},{"platform":"tiktok","handle":"mara.firstlight","url":"https://www.tiktok.com/@mara.firstlight"}],"role":"owner"}},"keep_only_instagram_every_link_left_out_is_removed":{"summary":"Keep only Instagram: every link left out is removed","value":{"creatorId":"k97c2m4vx8r1q0d6s5t3n9p2w7y4h8b1","slug":"mara-lindgren","displayName":"Mara Lindgren","realName":null,"bio":"Landscape photographer. I plan every trip around the light and share the exact spots, times and parking so you can do the same.","email":"mara@example.com","avatarUrl":"https://quiet-heron-512.convex.cloud/api/storage/mara-lindgren-avatar.webp","socials":[{"platform":"instagram","handle":"mara.firstlight","url":"https://www.instagram.com/mara.firstlight/","followerCount":184000}],"role":"owner"}}}}}},"400":{"description":"Invalid request: invalid_argument, invalid_request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}},"invalid_request":{"summary":"The input was refused","value":{"error":{"code":"invalid_request","message":"A writer refused a value: a map link on a host that is not allowed, a title that is too long, a date that does not exist, too many items in a list. The message is the writer's own sentence."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: api_scope_required, forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"api_scope_required":{"summary":"The key lacks a scope","value":{"error":{"code":"api_scope_required","message":"A read-only key called a write operation, or a key without the publish option called publish_changes."}}},"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"413":{"description":"Too large: payload_too_large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"payload_too_large":{"summary":"The request is too large","value":{"error":{"code":"payload_too_large","message":"A JSON body over 2 MB, an image over 6 MB, a batch upload over 19 MB, or an MCP message over 2 MB."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}}},"/media/upload":{"post":{"operationId":"upload_media","summary":"Upload a photo (raw bytes or multipart)","description":"Send the image as the raw body (Content-Type image/jpeg, image/png or image/webp) with the fields on the query string, or as multipart/form-data with a file field plus the same fields. The server checks the real file type, applies the EXIF rotation, scales the long side to 2048 px, stores WebP without EXIF, GPS, XMP or IPTC metadata (the capture date is kept as capturedOn) and makes a 640 px thumbnail for media rows. At most 6 MB and 6000 px per side: resize and compress first. target=blob returns a storageId for chapter covers and intro photos instead of a media row. Upload each photo once; update_media changes its fields later.","tags":["media"],"x-scope":"write","x-stability":"stable","x-since":"2026-09-17","x-mcp-tool":null,"parameters":[{"name":"ownerType","in":"query","required":false,"description":"What the photo belongs to: a spot, the guide (store thumbnail and sales page material), a chapter, or the sales page. Required unless target is blob.","schema":{"enum":["spot","product","collection","listing"]}},{"name":"ownerId","in":"query","required":false,"description":"Id of the owner row (spotId, productId, collectionId or listingId). Required unless target is blob.","schema":{"type":"string"}},{"name":"target","in":"query","required":false,"description":"media (the default) registers a photo; blob stores the file and returns a storageId for coverStorageId (update_chapter) or photoStorageId (set_chapter_intro).","schema":{"enum":["media","blob"]}},{"name":"caption","in":"query","required":false,"description":"Caption buyers read under the photo.","schema":{"type":"string"}},{"name":"credit","in":"query","required":false,"description":"Photographer credit, rendered as Photo: Name. Every photo that is not the creator's own carries one.","schema":{"type":"string"}},{"name":"alt","in":"query","required":false,"description":"Alt text: what the photo shows, for screen readers.","schema":{"type":"string"}},{"name":"focalX","in":"query","required":false,"description":"Focal point 0 (left) to 1 (right); the apps keep it in frame when they crop.","schema":{"type":"number"}},{"name":"focalY","in":"query","required":false,"description":"Focal point 0 (top) to 1 (bottom).","schema":{"type":"number"}},{"name":"sourcePageUrl","in":"query","required":false,"description":"The page the photo was licensed from (not the image file).","schema":{"type":"string"}},{"name":"licence","in":"query","required":false,"description":"Licence name (Unsplash License, CC BY 4.0).","schema":{"type":"string"}},{"name":"creditUrl","in":"query","required":false,"description":"The photographer's profile page.","schema":{"type":"string"}},{"name":"capturedOn","in":"query","required":false,"description":"Capture date (YYYY-MM-DD). Read from the file's metadata when absent.","schema":{"type":"string"}},{"name":"locationVerifiedBy","in":"query","required":false,"description":"How the photo's location was confirmed.","schema":{"enum":["geotag","landmark","photographer_caption","creator","other"]}},{"name":"reviewNotes","in":"query","required":false,"description":"Notes for the creator's review; never shown to buyers.","schema":{"type":"string"}},{"name":"meta","in":"query","required":false,"description":"A JSON object with any of the fields above plus shows ({ kind, label? }) and takenAt ({ lat, lon, precision }). On the query string it is JSON text.","schema":{"type":"object"}}],"requestBody":{"required":true,"content":{"image/jpeg":{"schema":{"type":"string","format":"binary"}},"image/png":{"schema":{"type":"string","format":"binary"}},"image/webp":{"schema":{"type":"string","format":"binary"}},"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary","description":"The image file."},"ownerType":{"enum":["spot","product","collection","listing"],"description":"What the photo belongs to: a spot, the guide (store thumbnail and sales page material), a chapter, or the sales page. Required unless target is blob."},"ownerId":{"type":"string","description":"Id of the owner row (spotId, productId, collectionId or listingId). Required unless target is blob."},"target":{"enum":["media","blob"],"description":"media (the default) registers a photo; blob stores the file and returns a storageId for coverStorageId (update_chapter) or photoStorageId (set_chapter_intro)."},"caption":{"type":"string","description":"Caption buyers read under the photo."},"credit":{"type":"string","description":"Photographer credit, rendered as Photo: Name. Every photo that is not the creator's own carries one."},"alt":{"type":"string","description":"Alt text: what the photo shows, for screen readers."},"focalX":{"type":"number","description":"Focal point 0 (left) to 1 (right); the apps keep it in frame when they crop."},"focalY":{"type":"number","description":"Focal point 0 (top) to 1 (bottom)."},"sourcePageUrl":{"type":"string","description":"The page the photo was licensed from (not the image file)."},"licence":{"type":"string","description":"Licence name (Unsplash License, CC BY 4.0)."},"creditUrl":{"type":"string","description":"The photographer's profile page."},"capturedOn":{"type":"string","description":"Capture date (YYYY-MM-DD). Read from the file's metadata when absent."},"locationVerifiedBy":{"enum":["geotag","landmark","photographer_caption","creator","other"],"description":"How the photo's location was confirmed."},"reviewNotes":{"type":"string","description":"Notes for the creator's review; never shown to buyers."},"meta":{"type":"object","description":"A JSON object with any of the fields above plus shows ({ kind, label? }) and takenAt ({ lat, lon, precision }). On the query string it is JSON text."}},"required":["file"]}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/UploadedPhoto"},{"$ref":"#/components/schemas/UploadedBlob"}]},"examples":{"upload_a_spot_photo_as_the_raw_body_fields_on_the_query_string":{"summary":"Upload a spot photo as the raw body, fields on the query string","value":{"mediaId":"kg71s3d5f7g9h1j3k5k7z9x1c3v5b7n9","url":"https://quiet-heron-512.convex.cloud/api/storage/grand-prismatic-overlook.webp","thumbUrl":"https://quiet-heron-512.convex.cloud/api/storage/grand-prismatic-overlook-640.webp","ownerType":"spot","ownerId":"k1709e2vj4sk8q6x0d3m5r7t9w1y3b5c","caption":"Grand Prismatic Spring from the overlook, mid morning","credit":"Mara Lindgren","order":1024,"contentType":"image/webp","width":2048,"height":1365,"bytes":684312,"originalBytes":5412880,"optimized":true,"metadataStripped":true,"thumbBytes":61240,"capturedOn":"2026-09-14"}},"structured_fields_shows_takenat_travel_in_meta_as_json_text":{"summary":"Structured fields (shows, takenAt) travel in meta as JSON text","value":{"mediaId":"kg7m9n1b3v5c7x9z1k3k5j7h9g1f3d5s","url":"https://quiet-heron-512.convex.cloud/api/storage/tunnel-view-after-storm.webp","thumbUrl":"https://quiet-heron-512.convex.cloud/api/storage/tunnel-view-after-storm-640.webp","ownerType":"spot","ownerId":"k17bc3xz8h6f4d2s0q9w7e5r3t1y2v4j","caption":null,"credit":"Mara Lindgren","order":1024,"contentType":"image/webp","width":1365,"height":2048,"bytes":548770,"originalBytes":4102555,"optimized":true,"metadataStripped":true,"thumbBytes":47316,"capturedOn":"2026-06-12"}},"store_a_chapter_cover_target_blob_returns_a_storageid_no_media_row":{"summary":"Store a chapter cover (target=blob returns a storageId, no media row)","value":{"storageId":"kg2a8c4e0g6j2k8m4p0q6s2v8w4y0a6c","contentType":"image/webp","width":2048,"height":1152,"bytes":402118,"originalBytes":3170912,"optimized":true,"metadataStripped":true,"use":"Pass storageId as coverStorageId (update_chapter) or photoStorageId (set_chapter_intro sections)"}}}}}},"400":{"description":"Invalid request: invalid_argument, invalid_request, unsupported_image, image_too_large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}},"invalid_request":{"summary":"The input was refused","value":{"error":{"code":"invalid_request","message":"A writer refused a value: a map link on a host that is not allowed, a title that is too long, a date that does not exist, too many items in a list. The message is the writer's own sentence."}}},"unsupported_image":{"summary":"Not a JPEG, PNG or WebP","value":{"error":{"code":"unsupported_image","message":"An upload's bytes are not a JPEG, PNG or WebP file, or their dimensions cannot be read. The bytes are checked, not the Content-Type header."}}},"image_too_large":{"summary":"The photo is too large","value":{"error":{"code":"image_too_large","message":"An upload is more than 6,000 px on a side."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: api_scope_required, forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"api_scope_required":{"summary":"The key lacks a scope","value":{"error":{"code":"api_scope_required","message":"A read-only key called a write operation, or a key without the publish option called publish_changes."}}},"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"404":{"description":"Not found: not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"Not found","value":{"error":{"code":"not_found","message":"The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists."}}}}}}},"413":{"description":"Too large: payload_too_large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"payload_too_large":{"summary":"The request is too large","value":{"error":{"code":"payload_too_large","message":"A JSON body over 2 MB, an image over 6 MB, a batch upload over 19 MB, or an MCP message over 2 MB."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}}},"/media/upload-batch":{"post":{"operationId":"upload_media_batch","summary":"Upload up to 10 photos in one request","description":"multipart/form-data with one form field per file and a manifest field: a JSON array with one item per file, naming the form field (file) and the same fields as upload_media ({ file, ownerType, ownerId, caption, credit, alt, ... } or { file, target: \"blob\" }). Every file counts against the upload limit and succeeds or fails on its own; the response lists each result. The status is 201 when at least one file was stored and 400 when every file failed, with the same body. At most 10 files and 19 MB per request.","tags":["media"],"x-scope":"write","x-stability":"beta","x-since":"2026-09-30","x-mcp-tool":null,"parameters":[],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"manifest":{"type":"string","description":"JSON array, one item per file: { file (the form field name), ownerType, ownerId, and any upload_media field }, or { file, target: \"blob\" }."}},"required":["manifest"],"additionalProperties":{"type":"string","format":"binary","description":"One form field per file, named as its manifest item's file."}}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchUpload"},"examples":{"two_spot_photos_and_a_chapter_cover_in_one_request":{"summary":"Two spot photos and a chapter cover in one request","value":{"uploaded":3,"failed":0,"results":[{"file":"overlook","ok":true,"mediaId":"kg71s3d5f7g9h1j3k5k7z9x1c3v5b7n9","url":"https://quiet-heron-512.convex.cloud/api/storage/grand-prismatic-overlook.webp","thumbUrl":"https://quiet-heron-512.convex.cloud/api/storage/grand-prismatic-overlook-640.webp","ownerType":"spot","ownerId":"k1709e2vj4sk8q6x0d3m5r7t9w1y3b5c","caption":"Grand Prismatic Spring from the overlook, mid morning","credit":"Mara Lindgren","width":2048,"height":1365,"order":1024,"contentType":"image/webp","bytes":684312,"thumbBytes":61240,"originalBytes":5412880,"optimized":true,"metadataStripped":true,"capturedOn":"2026-09-14"},{"file":"boardwalk","ok":true,"mediaId":"kg7p2p4j6v8y0t2r4e6w8q0a2s4d6f8g","url":"https://quiet-heron-512.convex.cloud/api/storage/grand-prismatic-aerial.webp","thumbUrl":"https://quiet-heron-512.convex.cloud/api/storage/grand-prismatic-aerial-640.webp","ownerType":"spot","ownerId":"k1709e2vj4sk8q6x0d3m5r7t9w1y3b5c","caption":"Grand Prismatic Spring and Midway Geyser Basin from above","credit":"Brocken Inaglory","width":2048,"height":1365,"order":2048,"contentType":"image/webp","bytes":597004,"thumbBytes":55872,"originalBytes":2811264,"optimized":true,"metadataStripped":false,"capturedOn":null,"warnings":["creditUrl uses http, not https: http://commons.wikimedia.org/wiki/User:Brocken_Inaglory"]},{"file":"yellowstone-cover","ok":true,"storageId":"kg2a8c4e0g6j2k8m4p0q6s2v8w4y0a6c","contentType":"image/webp","width":2048,"height":1152,"bytes":402118,"originalBytes":3170912,"optimized":true,"metadataStripped":true,"use":"Pass storageId as coverStorageId (update_chapter) or photoStorageId (set_chapter_intro sections)"}]}},"each_file_succeeds_or_fails_on_its_own_an_oversized_panorama_is_refused":{"summary":"Each file succeeds or fails on its own: an oversized panorama is refused","value":{"uploaded":1,"failed":1,"results":[{"file":"tunnel-view","ok":true,"mediaId":"kg7m9n1b3v5c7x9z1k3k5j7h9g1f3d5s","url":"https://quiet-heron-512.convex.cloud/api/storage/tunnel-view-after-storm.webp","thumbUrl":"https://quiet-heron-512.convex.cloud/api/storage/tunnel-view-after-storm-640.webp","ownerType":"spot","ownerId":"k17bc3xz8h6f4d2s0q9w7e5r3t1y2v4j","caption":"Tunnel View after a storm cleared","credit":"Mara Lindgren","width":1365,"height":2048,"order":1024,"contentType":"image/webp","bytes":548770,"thumbBytes":47316,"originalBytes":4102555,"optimized":true,"metadataStripped":true,"capturedOn":"2026-06-12"},{"file":"tunnel-view-panorama","ok":false,"error":{"code":"image_too_large","message":"Images must be at most 6000 px per side (got 9120x2560); resize to 2048 px on the long side"}}]}}}}}},"400":{"description":"Invalid request: invalid_argument, invalid_request, unsupported_image, image_too_large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_argument":{"summary":"A field has the wrong shape","value":{"error":{"code":"invalid_argument","message":"A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message)."}}},"invalid_request":{"summary":"The input was refused","value":{"error":{"code":"invalid_request","message":"A writer refused a value: a map link on a host that is not allowed, a title that is too long, a date that does not exist, too many items in a list. The message is the writer's own sentence."}}},"unsupported_image":{"summary":"Not a JPEG, PNG or WebP","value":{"error":{"code":"unsupported_image","message":"An upload's bytes are not a JPEG, PNG or WebP file, or their dimensions cannot be read. The bytes are checked, not the Content-Type header."}}},"image_too_large":{"summary":"The photo is too large","value":{"error":{"code":"image_too_large","message":"An upload is more than 6,000 px on a side."}}}}}}},"401":{"description":"Missing or invalid API key: unauthenticated, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"No API key","value":{"error":{"code":"unauthenticated","message":"The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key)."}}},"invalid_api_key":{"summary":"The key does not work","value":{"error":{"code":"invalid_api_key","message":"The key is unknown, revoked or expired."}}}}}}},"403":{"description":"The key may not do this: api_scope_required, forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"api_scope_required":{"summary":"The key lacks a scope","value":{"error":{"code":"api_scope_required","message":"A read-only key called a write operation, or a key without the publish option called publish_changes."}}},"forbidden":{"summary":"The key has no creator","value":{"error":{"code":"forbidden","message":"The key belongs to a creator account that is no longer active."}}}}}}},"413":{"description":"Too large: payload_too_large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"payload_too_large":{"summary":"The request is too large","value":{"error":{"code":"payload_too_large","message":"A JSON body over 2 MB, an image over 6 MB, a batch upload over 19 MB, or an MCP message over 2 MB."}}}}}}},"429":{"description":"Rate limited: rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"Too many requests","value":{"error":{"code":"rate_limited","message":"Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour."}}}}}}},"500":{"description":"Internal error: internal_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"summary":"Something failed on our side","value":{"error":{"code":"internal_error","message":"An unexpected failure. The message is hidden on purpose."}}}}}}}}}}}}