# update_itinerary

Edit trip fields or hide an itinerary from buyers.

`PATCH /v1/itineraries/{itineraryId}` · MCP tool `update_itinerary` · scope `write` · beta · since 2026-10-06.3

Only sent fields change. Empty string clears a string except name, which must stay nonempty; null clears the cover, travel mode and season. archived true hides the itinerary from buyers and keeps it editable: write a long trip across several publishes, then set archived false when ready. There is no separate archive operation. Days go through set_itinerary_days. The reply is the stored, normalized row and its updatedAt for the next edit.

## Path parameters

- `itineraryId` (string, required): Id of the itinerary, from list_itineraries or create_itinerary.

## Body parameters

- `archived` (boolean, optional): True hides this trip from buyers and keeps it editable; false makes it eligible at the next publish.
- `body` (string, optional): Before you go: who the trip suits, what to book and the pace, at most 5000 characters. Empty string clears.
- `coverMediaId` (string or null, optional): A photo of this guide, from list_media. Null clears.
- `description` (string, optional): Short description, at most 300 characters. Empty string clears.
- `endsAt` (string, optional): Where the trip ends, in words, at most 120 characters. Empty string clears.
- `expectedUpdatedAt` (number, optional): Optional staleness guard: the itinerary's updatedAt from your last read or write reply. A changed row refuses with stale_editor; read it again before editing.
- `name` (string, optional): Trip name, required when sent, at most 120 characters. Cannot be empty.
- `season` (ItinerarySeason or null, optional): Months and a season note. Null or an empty object clears.
  Fields of ItinerarySeason: https://developers.sceniq.earth/fields/itinerary-season.md
- `startsAt` (string, optional): Where the trip starts, in words, at most 120 characters. Empty string clears.
- `travelMode` (string or null, optional): Getting around on the whole trip: car, public_transport, campervan, bike, on_foot, boat, mixed. Null clears. One of `car`, `public_transport`, `campervan`, `bike`, `on_foot`, `boat`, `mixed`.

## Returns

200: ItineraryWrite.

- `itineraryId` (string, required): The itinerary's id.
- `productId` (string, required): The guide's id.
- `name` (string, required): The trip's name.
- `description` (string or null, required): Short description, or null when empty.
- `body` (string or null, required): Before you go: the creator's trip notes, or null.
- `coverMediaId` (string or null, required): A photo of this guide, or null for no cover.
- `travelMode` (string or null, required): How to get around on the whole trip, or null when unknown. One of `car`, `public_transport`, `campervan`, `bike`, `on_foot`, `boat`, `mixed`.
- `season` (ItinerarySeason or null, required): Months and a season note, or null when unset.
  Fields of ItinerarySeason: https://developers.sceniq.earth/fields/itinerary-season.md
- `startsAt` (string or null, required): Where the trip starts, in words, or null.
- `endsAt` (string or null, required): Where the trip ends, in words, or null.
- `days` (array of ItineraryDay, required): The days exactly as stored, with absent optional fields and no nulls inside. Edit this array and send it straight to set_itinerary_days.
  Fields of ItineraryDay: https://developers.sceniq.earth/fields/itinerary-day.md
- `order` (number, required): Position in the guide, ascending and fractional.
- `archived` (boolean, required): true hides this itinerary from buyers and keeps it editable.
- `createdAt` (number, required): When the row was created (Unix time in milliseconds).
- `updatedAt` (number, required): When the row last changed (Unix time in milliseconds).
- `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

### Keep a trip editable and hidden while the creator works on it

```bash
curl -X PATCH "https://sceniq.earth/api/v1/itineraries/ki7a2c4e6g8j0m2p4s6v8y0b2d4f6h8k" \
  -H "Authorization: Bearer $SCENIQ_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "archived": true,
  "coverMediaId": null,
  "expectedUpdatedAt": 1790586840000
}'
```

MCP `tools/call`:

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "update_itinerary",
    "arguments": {
      "itineraryId": "ki7a2c4e6g8j0m2p4s6v8y0b2d4f6h8k",
      "archived": true,
      "coverMediaId": null,
      "expectedUpdatedAt": 1790586840000
    }
  }
}
```

Response 200:

```json
{
  "itineraryId": "ki7a2c4e6g8j0m2p4s6v8y0b2d4f6h8k",
  "productId": "j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2",
  "name": "Yellowstone over two days",
  "description": "Thermal colors, a night at Old Faithful and first light in Lamar Valley.",
  "body": "Book the inn ahead. Check road conditions and keep wildlife at a distance.",
  "coverMediaId": null,
  "travelMode": "car",
  "season": {
    "months": [
      6,
      7,
      8,
      9
    ],
    "note": "Check the park road status before setting out."
  },
  "startsAt": "Old Faithful",
  "endsAt": "Lamar Valley",
  "days": [
    {
      "title": "Thermal basins and the overlook",
      "note": "Wait for the steam to lift before the overlook.",
      "stops": [
        {
          "kind": "place",
          "facilityId": "k17d4f6g8h0j2k4k6z8x0c2v4b6n8m0q",
          "when": "morning"
        },
        {
          "kind": "route",
          "routeId": "kx7f2h8j4k0k6z2x8c4v0b6n2m8q4w0e",
          "when": "morning"
        },
        {
          "kind": "spot",
          "spotKey": "01M2Z1G0Y0QG7M2V6N9R3T5W8Y",
          "when": "midday",
          "note": "See the colors from the platform, then walk the boardwalk."
        },
        {
          "kind": "travel",
          "mode": "car",
          "from": "Midway Geyser Basin",
          "to": "Old Faithful",
          "when": "afternoon"
        },
        {
          "kind": "place",
          "facilityId": "k17j9h5g1f7d3s9a5p1p7j3v9y5t1r7m",
          "when": "evening"
        }
      ],
      "overnight": {
        "facilityId": "k17j9h5g1f7d3s9a5p1p7j3v9y5t1r7m",
        "name": "Old Faithful Inn",
        "note": "Reserve before the trip."
      }
    },
    {
      "title": "First light in Lamar Valley",
      "stops": [
        {
          "kind": "travel",
          "mode": "car",
          "from": "Old Faithful",
          "to": "Lamar Valley",
          "when": "night"
        },
        {
          "kind": "spot",
          "spotKey": "01M3GYV6A0Y3SYC62RBPEA9S0C",
          "when": "sunrise"
        },
        {
          "kind": "note",
          "title": "Keep wildlife at a distance",
          "note": "Follow the park's current wildlife guidance."
        }
      ]
    }
  ],
  "order": 1024,
  "archived": true,
  "createdAt": 1789895640000,
  "updatedAt": 1790673240000
}
```

## 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.
- `stale_editor` (409): The row changed after the expectedUpdatedAt you sent (update_chapter, set_chapter_pages, update_itinerary, set_itinerary_days, save_sales_page_draft).
- `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_itinerary
