# set_itinerary_days

Replace all days and stops of an itinerary.

`PUT /v1/itineraries/{itineraryId}/days` · MCP tool `set_itinerary_days` · scope `write` · beta · since 2026-10-06.3

Full replacement: send 1 to 30 days in order, with 0 to 40 stops each. Positions are the identity, with no ids inside days or stops. Every referenced spot, route, place or stay must belong to this guide; another guide's reference refuses with its position, for example Day 2, stop 3: this spot is not in the guide. Archived spots are accepted with warnings and buyers do not see those stops. Helpers are place stops by their spotId, never spot stops. The reply is the stored row with optional warnings and updatedAt. The whole itinerary must fit 100000 JSON characters.

## Path parameters

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

## Body parameters

- `days` (array of ItineraryDay, required): All desired days, in order, 1 to 30. Read days back as stored before the next edit.
  Fields of ItineraryDay: https://developers.sceniq.earth/fields/itinerary-day.md
- `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.

## 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

### Second call: replace the days, with travel minutes left empty

```bash
curl -X PUT "https://sceniq.earth/api/v1/itineraries/ki7a2c4e6g8j0m2p4s6v8y0b2d4f6h8k/days" \
  -H "Authorization: Bearer $SCENIQ_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "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."
        }
      ]
    }
  ],
  "expectedUpdatedAt": 1790673240000
}'
```

MCP `tools/call`:

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "set_itinerary_days",
    "arguments": {
      "itineraryId": "ki7a2c4e6g8j0m2p4s6v8y0b2d4f6h8k",
      "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."
            }
          ]
        }
      ],
      "expectedUpdatedAt": 1790673240000
    }
  }
}
```

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": "kg71s3d5f7g9h1j3k5k7z9x1c3v5b7n9",
  "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": false,
  "createdAt": 1790673240000,
  "updatedAt": 1790673240001
}
```

## 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/set_itinerary_days
