# update_facility

Edit a place.

`PATCH /v1/facilities/{facilityId}` · MCP tool `update_facility` · scope `write` · stable · since 2026-09-17

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.

## Path parameters

- `facilityId` (string, required): Id of the facility (from list_facilities).

## Body parameters

- `activity` (ActivityInfo or null, optional): Tours and activities (kind activity), null clears: { meetingPoint?, meetingLat?, meetingLon?, durationMin?, departures?, requiredToSee? (the only way to see the spot), authorizedBy?, authorizedByUrl? }.
  Fields of ActivityInfo: https://developers.sceniq.earth/fields/activity-info.md
- `bookingRequired` (boolean, optional): true shows Booking required.
- `bookingUrl` (string, optional): The page to book on (http or https).
- `conditions` (PlaceConditions or null, optional): null clears: { minAge?, guestsOnly?, swimmersOnly?, luggageKg?, soldAsPackage?, cashOnly? }, shown as chips.
  Fields of PlaceConditions: https://developers.sceniq.earth/fields/place-conditions.md
- `costRaw` (string, optional): 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` (string or null, optional): What costRaw counts: per_person, per_night, per_person_night, per_room, per_vehicle, per_trip, per_hour, per_day. null clears. One of `per_person`, `per_night`, `per_person_night`, `per_room`, `per_vehicle`, `per_trip`, `per_hour`, `per_day`.
- `country` (string, optional): ISO 3166-1 alpha-2 code (AR, BR): places on two sides of a border read right.
- `description` (string, optional): The place in the creator's words. Empty string clears.
- `extraKinds` (array of strings, optional): Further roles of the same place (a hut that is also a restaurant): [hut|cable_car|activity|food|parking]. It then shows under each. One of `hut`, `cable_car`, `activity`, `food`, `parking`.
- `extraProps` (array of ExtraProp, optional): 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.
  Fields of ExtraProp: https://developers.sceniq.earth/fields/extra-prop.md
- `factsCheckedOn` (string, optional): The day the facts were last checked against their sources (YYYY-MM-DD). Empty string clears.
- `fees` (array of Fee, optional): 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.
  Fields of Fee: https://developers.sceniq.earth/fields/fee.md
- `gatewayTown` (string, optional): 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` (string, optional): Google place id the pin came from, as a reference.
- `insideId` (string or null, optional): facilityId of the place this one sits inside (a restaurant inside a lodge); one level only. null clears.
- `kind` (string, optional): 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. One of `hut`, `cable_car`, `activity`, `food`, `parking`.
- `lat` (number or null, optional): The place's own latitude. With lon, the apps show it on the map and compute its distance to the spot; null clears.
- `links` (array of GuideLink, optional): 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.
  Fields of GuideLink: https://developers.sceniq.earth/fields/guide-link.md
- `lon` (number or null, optional): The place's own longitude.
- `mapsUrl` (string, optional): 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` (string, optional): Name of the place. Cannot be empty.
- `needsParentTicket` (boolean, optional): true when entering needs the parent place's ticket.
- `openRaw` (string, optional): Season or hours as text, never parsed (schedule holds structured hours). Empty string clears.
- `operator` (string, optional): Who runs it. Empty string clears.
- `osmId` (string, optional): OpenStreetMap reference the pin came from: node/123, way/456 or relation/789.
- `parking` (ParkingInfo or null, optional): Parking places, null clears: { fillsBy? (10:00), rule? (the only legal pullout) }.
  Fields of ParkingInfo: https://developers.sceniq.earth/fields/parking-info.md
- `reviewBy` (string, optional): 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` (string, optional): 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` (Schedule or null, optional): 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.
  Fields of Schedule: https://developers.sceniq.earth/fields/schedule.md
- `sources` (array of SourceRef, optional): 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) }].
  Fields of SourceRef: https://developers.sceniq.earth/fields/source-ref.md
- `spotKeys` (array of strings, optional): 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` (StatusNotice or null, optional): 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.
  Fields of StatusNotice: https://developers.sceniq.earth/fields/status-notice.md
- `transport` (TransportInfo or null, optional): Transport places, null clears: { stops?: [{ name, lat?, lon?, registerId? (NSR or GTFS stop id), note? }], serviceDays? [1-7], timetableUrl?, timetableValidFrom?, timetableValidUntil?, verifyBeforeTravel? }.
  Fields of TransportInfo: https://developers.sceniq.earth/fields/transport-info.md
- `type` (string, optional): 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` (string, optional): Link to the official site (https, or http with a warning). Empty string clears.

## Returns

200.

- `ok` (boolean, required): Always true: the write went through. Always `true`.
- `facilityId` (string, required): The place's id.
- `warnings` (array of strings, optional): Notes about things the write accepted but you should look at (a plain http link). Present only when there are any.

## Examples

### Post a notice and record when the lot fills

```bash
curl -X PATCH "https://sceniq.earth/api/v1/facilities/km7d4f6g8h0j2k4k6z8x0c2v4b6n8m0q" \
  -H "Authorization: Bearer $SCENIQ_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "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"
}'
```

MCP `tools/call`:

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "update_facility",
    "arguments": {
      "facilityId": "km7d4f6g8h0j2k4k6z8x0c2v4b6n8m0q",
      "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"
    }
  }
}
```

Response 200:

```json
{
  "ok": true,
  "facilityId": "km7d4f6g8h0j2k4k6z8x0c2v4b6n8m0q"
}
```

### Clear fields: null clears an object, an empty string clears text

```bash
curl -X PATCH "https://sceniq.earth/api/v1/facilities/km73j9h5g1f7d3s9a5p1p7j3v9y5t1r7" \
  -H "Authorization: Bearer $SCENIQ_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "status": null,
  "reviewNotes": ""
}'
```

MCP `tools/call`:

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "update_facility",
    "arguments": {
      "facilityId": "km73j9h5g1f7d3s9a5p1p7j3v9y5t1r7",
      "status": null,
      "reviewNotes": ""
    }
  }
}
```

Response 200:

```json
{
  "ok": true,
  "facilityId": "km73j9h5g1f7d3s9a5p1p7j3v9y5t1r7"
}
```

## Errors

- `invalid_argument` (400): 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` (400): 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.
- `unauthenticated` (401): The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key).
- `invalid_api_key` (401): The key is unknown, revoked or expired.
- `api_scope_required` (403): A read-only key called a write operation, or a key without the publish option called publish_changes.
- `forbidden` (403): The key belongs to a creator account that is no longer active.
- `not_found` (404): The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists.
- `payload_too_large` (413): A JSON body over 2 MB, an image over 6 MB, a batch upload over 19 MB, or an MCP message over 2 MB.
- `rate_limited` (429): Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour.
- `internal_error` (500): An unexpected failure. The message is hidden on purpose.

Reference: https://developers.sceniq.earth/reference/update_facility
