Docs

Roadbook MCP API

See what is included in Premium

Roadbook exposes a Model Context Protocol(MCP) server so an AI agent can plan and manage trips on a user's behalf. The endpoint speaks JSON-RPC 2.0 over a single route.

Endpoint

POST /mcp accepts a JSON-RPC 2.0 request (or a batch array of up to 50) and dispatches on the methodfield - initialize,tools/list, andtools/call are the ones an MCP client needs. The machine-readable request/response envelope is published as OpenAPI at/openapi.json. Every tool and its input fields are listed under Tools.

Authentication

Every request needs a bearer token in the Authorization header. Two ways to get one:

  • OAuth 2.0 - discover the authorization server at/.well-known/oauth-authorization-server(RFC 8414) and the protected-resource metadata at/.well-known/oauth-protected-resource(RFC 9728). Dynamic client registration, PKCE (S256), and theauthorization_code andrefresh_token grants are supported.
  • Personal token - a signed-in user can mint a long-lived token from their account settings for scripting or local MCP clients that don't support OAuth.

Access

Connecting and listing tools is free. Every tool call needs an active premium subscription. Any authenticated, non-banned Roadbook account can run initialize and tools/list. The premium check runs at tools/call time, not at connection time.

Tools

29 tools, generated from the server's own tools/list response, so every field below is one a client sees. Each badge says what a tool does to your data, not which plan can call it. The badge comes from the tool's MCP annotations: Read-only never changes data, Writes adds or edits, and Destructive can remove data.

list_tripsRead-only

List trips

List the trips you own (id, name, slug, visibility).

FieldTypeRequiredNotes
session_idstringOptionalGroups this call with others in the same task.
agent_idstringOptionalDistinguishes this agent from others running in parallel.
intentstringOptionalWhy you are calling this tool.

read_tripRead-only

Read trip

Read one of your trips with its stops in order, each with name/city/state, nights, and public place coordinates only (never planner-only coordinates), plus trip.startDate and trip.endDate. Call this FIRST before saving a trip transcript to the logbook: match each place named in the transcript to a stop by its public identity (name/city/state - never coordinates), then derive each matched stop's date as trip.startDate plus the cumulative nights of every earlier stop (or the transcript's stated date when it gives one). File the resulting entries with create_journal_entries.

FieldTypeRequiredNotes
tripIdstringRequiredTrip id
session_idstringOptionalGroups this call with others in the same task.
agent_idstringOptionalDistinguishes this agent from others running in parallel.
intentstringOptionalWhy you are calling this tool.

create_tripWrites

Create trip

Create a new private trip. Provide a name; optionally a startDate and endDate (YYYY-MM-DD).

FieldTypeRequiredNotes
namestringRequiredTrip name
startDatestringOptionalISO date YYYY-MM-DD (optional)
endDatestringOptionalISO date YYYY-MM-DD (optional)
session_idstringOptionalGroups this call with others in the same task.
agent_idstringOptionalDistinguishes this agent from others running in parallel.
intentstringOptionalWhy you are calling this tool.

search_placesRead-only

Search places

Search for real places by name. Give a destination name or query only - never coordinates. The server resolves it to a real place. Returns candidate matches to confirm before adding.

FieldTypeRequiredNotes
querystringRequiredDestination name or query
session_idstringOptionalGroups this call with others in the same task.
agent_idstringOptionalDistinguishes this agent from others running in parallel.
intentstringOptionalWhy you are calling this tool.

add_stopWrites

Add stop

Add a stop to a trip by destination name/query. Give a destination name or query only - never coordinates. The server resolves it to a real place. On an ambiguous match nothing is created and each returned candidate carries a "ref" - call add_stop again with tripId and candidateRef (query not required) to add the exact one meant. Optionally place it precisely: set beforeWaypointId to an existing top-level stop id (from read_trip) to insert the new stop immediately before it; omit beforeWaypointId to append at the end, as before. If you're repeating this call to resolve an ambiguous match with candidateRef, pass beforeWaypointId again too - it is not remembered from the first call. Optionally record lodging for this stop in the same call: set lodgingName (required once any lodging field is set) plus any of lodgingType, checkIn/checkOut, cost, currency, reservationRef, lodgingNotes.

FieldTypeRequiredNotes
tripIdstringRequiredTrip id
querystringOptionalDestination name or query
candidateRefstringOptionalA "ref" from a previous ambiguous add_stop result - use instead of query to add that exact candidate
rolestringOptionaldeparture | stop | destination (default stop)
beforeWaypointIdstringOptionalInsert the new stop immediately before this existing top-level stop id (from read_trip). Omit - or send an empty string - to append at the end.
lodgingNamestring | nullOptional
lodgingType"campground" | "hotel" | "motel" | "inn" | "rental" | "dispersed" | "other" | nullOptionalType of lodging: campground, hotel, motel, inn, rental, dispersed, other
checkInstring | nullOptional
checkOutstring | nullOptional
costnumber | nullOptionalCost of the stay
currencystring | nullOptional
reservationRefstring | nullOptional
lodgingNotesstring | nullOptional
session_idstringOptionalGroups this call with others in the same task.
agent_idstringOptionalDistinguishes this agent from others running in parallel.
intentstringOptionalWhy you are calling this tool.

update_stopWrites

Update stop

Update a stop on your trip: its role, number of nights, and/or its lodging booking (lodgingName, lodgingType, checkIn/checkOut, cost, currency, reservationRef, lodgingNotes). lodgingName is required the first time lodging is recorded for this stop; once set it cannot be cleared. Pass null (or an empty string) on any other lodging field to clear it, or omit a field to leave it unchanged. To detach a booking from this stop entirely, use remove_stop_lodging.

FieldTypeRequiredNotes
tripIdstringRequiredTrip id
waypointIdstringRequiredStop id
rolestringOptionaldeparture | stop | destination
nightsintegerOptionalNights at this stop
lodgingNamestring | nullOptional
lodgingType"campground" | "hotel" | "motel" | "inn" | "rental" | "dispersed" | "other" | nullOptionalType of lodging: campground, hotel, motel, inn, rental, dispersed, other
checkInstring | nullOptional
checkOutstring | nullOptional
costnumber | nullOptionalCost of the stay
currencystring | nullOptional
reservationRefstring | nullOptional
lodgingNotesstring | nullOptional
session_idstringOptionalGroups this call with others in the same task.
agent_idstringOptionalDistinguishes this agent from others running in parallel.
intentstringOptionalWhy you are calling this tool.

remove_stopDestructive

Remove stop

Remove a stop from your trip.

FieldTypeRequiredNotes
tripIdstringRequiredTrip id
waypointIdstringRequiredStop id
session_idstringOptionalGroups this call with others in the same task.
agent_idstringOptionalDistinguishes this agent from others running in parallel.
intentstringOptionalWhy you are calling this tool.

remove_stop_lodgingDestructive

Remove stop lodging

Remove one lodging record from a stop on your trip, without removing the stop. The stop keeps its place, position, nights, charging report and every logbook entry tagged to it. Pass the lodgingId from read_trip to name the exact record. Omit lodgingId only when the stop has a single lodging record; if the stop has none this reports that there was nothing to remove, and if it has several it asks you to name one. Deletion cannot be undone.

FieldTypeRequiredNotes
tripIdstringRequiredTrip id
waypointIdstringRequiredStop id
lodgingIdstringOptionalId of the lodging record to remove, from read_trip (optional when the stop has exactly one)
session_idstringOptionalGroups this call with others in the same task.
agent_idstringOptionalDistinguishes this agent from others running in parallel.
intentstringOptionalWhy you are calling this tool.

reorder_stopsWrites

Reorder stops

Reorder all stops on your trip. Pass every stop id in the new order.

FieldTypeRequiredNotes
tripIdstringRequiredTrip id
waypointIdsstring[]RequiredAll stop ids, in the new order
session_idstringOptionalGroups this call with others in the same task.
agent_idstringOptionalDistinguishes this agent from others running in parallel.
intentstringOptionalWhy you are calling this tool.

list_journal_entriesRead-only

List logbook entries

Operates on the PRIVATE LOGBOOK, never the public journal body. Lists the private logbook entries for one of your trips. Each entry includes its visibility ('private' or 'public').

FieldTypeRequiredNotes
tripIdstringRequiredTrip id
session_idstringOptionalGroups this call with others in the same task.
agent_idstringOptionalDistinguishes this agent from others running in parallel.
intentstringOptionalWhy you are calling this tool.

create_journal_entryWrites

Create logbook entry

Operates on the PRIVATE LOGBOOK, never the public journal body. Add a single private dated logbook entry (markdown). Optionally tag it to a stop. A note about the drive itself belongs on the arrival stop with scope: 'drive'. Entries are private by default. Only set visibility: 'public' when the user has explicitly asked for that entry to be public - never infer it. When splitting a whole trip transcript across multiple stops, use create_journal_entries instead so you file one entry per matched stop in a single call. Changing the logbook marks a published journal stale. The response echoes the tagged stop's recorded lodging as lodging (name, type, charger type). Compare it against the entry text you just wrote. If they disagree, tell the user which entry looks misfiled and which stop it probably belongs to instead of silently re-filing it. An entry with no stop tag comes back with a warnings entry saying it could not be checked - relay that to the user too.

FieldTypeRequiredNotes
tripIdstringRequiredTrip id
bodystringRequiredMarkdown note
entryDatestringRequiredISO date YYYY-MM-DD
waypointIdstringOptionalStop id to tag (optional)
scope"stay" | "drive"Optionalstay = about the time at the tagged stop (default); drive = about the leg that arrived at it (requires waypointId, and the first stop has no inbound drive)
visibility"private" | "public"Optionalprivate (default) = never leaves your view; public = eligible to appear publicly, and only ever when the trip itself is public. Set 'public' only when the user explicitly asks.
session_idstringOptionalGroups this call with others in the same task.
agent_idstringOptionalDistinguishes this agent from others running in parallel.
intentstringOptionalWhy you are calling this tool.

create_journal_entriesWrites

Create logbook entries (batch)

Operates on the PRIVATE LOGBOOK, never the public journal body. Add multiple private dated logbook entries (markdown) in one call - e.g. splitting an entire trip transcript into per-stop notes. Before calling, use read_trip to get the trip's stops (name/city/state, nights) and startDate. Match each transcript place to a real stop by public identity (name/city/state - never coordinates) and set that entry's waypointId; create at most one entry per matched stop, consolidating repeated mentions into it. Date each entry from the transcript when it states one, otherwise use the stop's planned date (startDate plus the cumulative nights of every earlier stop), formatted YYYY-MM-DD. Never create a stop or an entry for a transcript place that is not already a stop on this trip - report those unmatched places back to the user instead of guessing. Entries are private by default. Only set an entry's visibility: 'public' when the user has explicitly asked for that entry to be public - never infer it, and never mark a whole transcript public. Each entry may optionally tag a stop, and a note about the drive itself belongs on the arrival stop with scope: 'drive'. Validation is per-entry: the response reports each entry's outcome (created id, or its error) instead of failing the whole call. Max 50 entries per call. Changing the logbook marks a published journal stale. Each created entry's result carries its own lodging (the tagged stop's recorded booking name, type, charger type). Compare each entry's text against its lodging and, on a disagreement, tell the user which entry looks misfiled and which stop it probably belongs to instead of silently re-filing it. An entry with no stop tag carries a warnings entry saying it could not be checked - relay that too.

FieldTypeRequiredNotes
tripIdstringRequiredTrip id
entriesobject[]RequiredEntries to create, in order (max 50)
session_idstringOptionalGroups this call with others in the same task.
agent_idstringOptionalDistinguishes this agent from others running in parallel.
intentstringOptionalWhy you are calling this tool.

update_journal_entryWrites

Update logbook entry

Operates on the PRIVATE LOGBOOK, never the public journal body. Edit a private logbook entry (body, entryDate, scope, waypointId, and/or visibility). Pass waypointId to set/change the stop tag, or waypointId: null to clear it; omit waypointId entirely to leave the current tag untouched. Pass visibility to promote ('public') or demote ('private') an entry; a public entry is only ever exposed publicly when its trip is also public, and this tool renders nothing. Changing the logbook marks a published journal stale. The response echoes the entry's (post-update) tagged stop's recorded lodging as lodging (name, type, charger type). Compare it against the entry text and, on a disagreement, tell the user which entry looks misfiled and which stop it probably belongs to instead of silently re-filing it. An entry with no stop tag comes back with a warnings entry saying it could not be checked - relay that to the user too.

FieldTypeRequiredNotes
tripIdstringRequiredTrip id
entryIdstringRequiredEntry id
bodystringOptionalMarkdown note
entryDatestringOptionalISO date YYYY-MM-DD
waypointIdstringOptionalStop id to tag, or null to clear the tag (omit to leave the tag unchanged)
scope"stay" | "drive"Optionalstay = about the time at the tagged stop (default); drive = about the leg that arrived at it (requires waypointId, and the first stop has no inbound drive)
visibility"private" | "public"Optionalprivate (default) = never leaves your view; public = eligible to appear publicly, and only ever when the trip itself is public. Set 'public' only when the user explicitly asks.
session_idstringOptionalGroups this call with others in the same task.
agent_idstringOptionalDistinguishes this agent from others running in parallel.
intentstringOptionalWhy you are calling this tool.

delete_journal_entryDestructive

Delete logbook entry

Operates on the PRIVATE LOGBOOK, never the public journal body. Delete a private logbook entry. Changing the logbook marks a published journal stale.

FieldTypeRequiredNotes
tripIdstringRequiredTrip id
entryIdstringRequiredEntry id
session_idstringOptionalGroups this call with others in the same task.
agent_idstringOptionalDistinguishes this agent from others running in parallel.
intentstringOptionalWhy you are calling this tool.

read_journalRead-only

Read journal

Operates on the PUBLIC JOURNAL BODY, never the private logbook. Read the public trip journal state: body, draftBody, publishedAt, lastPublishedAt, source, style, stale, and changedEntryCount. `draftBody` is the pending private working draft written by write_journal (never public) - compare it against the live `body` to preview a draft before publishing. `stale` means the private logbook has changed since the body was last published, for any source (human, ai_preset, ai_assistant). `lastPublishedAt` is a sticky anchor set on every publish and never cleared on unpublish (null if never published). `changedEntryCount` is the number of logbook entries created or edited since `lastPublishedAt` (0 when never published) - a lower-bound scoping hint for a regeneration; a delete cannot be counted this way, so `stale` remains the authoritative change trigger.

FieldTypeRequiredNotes
tripIdstringRequiredTrip id
session_idstringOptionalGroups this call with others in the same task.
agent_idstringOptionalDistinguishes this agent from others running in parallel.
intentstringOptionalWhy you are calling this tool.

write_journalWrites

Draft journal

Operates on the PUBLIC JOURNAL BODY, never the private logbook. Write a draft of the public trip journal body (markdown). The draft is private and never touches the live published body or publish state, even when a journal is already published - it is safe to call any time. Read the draft back alongside the live body with read_journal, revise by calling this again (each call replaces the whole draft, no merge), then call publish_journal to promote the draft to the live public body.

FieldTypeRequiredNotes
tripIdstringRequiredTrip id
bodystringRequiredMarkdown journal body
session_idstringOptionalGroups this call with others in the same task.
agent_idstringOptionalDistinguishes this agent from others running in parallel.
intentstringOptionalWhy you are calling this tool.

publish_journalWrites

Publish journal

Operates on the PUBLIC JOURNAL BODY, never the private logbook. Publish the pending draft: promotes journalDraftBody to the live public body, sets publishedAt and the sticky lastPublishedAt anchor, clears the draft, and marks the body no longer stale. This is the explicit owner-directed act that makes AI-authored content public - throws if there is no draft to publish (write one with write_journal first).

FieldTypeRequiredNotes
tripIdstringRequiredTrip id
session_idstringOptionalGroups this call with others in the same task.
agent_idstringOptionalDistinguishes this agent from others running in parallel.
intentstringOptionalWhy you are calling this tool.

unpublish_journalWrites

Unpublish journal

Operates on the PUBLIC JOURNAL BODY, never the private logbook. Take the public trip journal offline: clears publishedAt only. Leaves the sticky lastPublishedAt anchor, the live body, and any pending draft unchanged, and never touches private logbook entries. Idempotent - calling this when already unpublished is a no-op that returns the current state, not an error.

FieldTypeRequiredNotes
tripIdstringRequiredTrip id
session_idstringOptionalGroups this call with others in the same task.
agent_idstringOptionalDistinguishes this agent from others running in parallel.
intentstringOptionalWhy you are calling this tool.

read_logbook_coverageRead-only

Read logbook coverage

Operates on the PRIVATE LOGBOOK, never the public journal body. Mechanically counts words/characters across one of your trips' logbook entries and returns trip-wide totals, per-day averages, and a per-overnight-stop words-per-night ranking (thinnest first) - no AI judgement of quality, sentiment, or style, and no suggestions for what to write. The per-day denominator is the trip's full planned span (nights + 1 across top-level stops), not elapsed time, so an in-progress trip's half-written logbook correctly reads as thin. Stops with 0 nights are excluded from the ranking (a per-night ratio is undefined for them) but still count toward totals.

FieldTypeRequiredNotes
tripIdstringRequiredTrip id
session_idstringOptionalGroups this call with others in the same task.
agent_idstringOptionalDistinguishes this agent from others running in parallel.
intentstringOptionalWhy you are calling this tool.

record_stop_chargingWrites

Record stop charging

Record EV charging attributes for a stop you own, as a community camp-and-charge report on that stop's place. chargingAvailable is required: false records the explicit negative (charging not permitted) and must not carry any other charging detail; true may optionally include chargingCost (free|paid|included), chargingPowerKw, chargingConnectorCount, chargingConnectorTypes, and chargingNotes. visitMonth defaults to the current month. Re-recording the same stop/month overwrites the previous report. Read it back via read_trip's per-stop chargingReport field. The stop must either be a place that accepts camp-and-charge reports (national park, state park, campground, hotel/lodge) or have lodging recorded on it.

FieldTypeRequiredNotes
tripIdstringRequiredTrip id
waypointIdstringRequiredStop id
chargingAvailablebooleanRequiredWhether EV charging is available/permitted at this stop
chargingCost"free" | "paid" | "included"OptionalHow charging is billed: free, paid, included
chargingPowerKwnumberOptionalCharging power in kW (> 0, <= 1000)
chargingConnectorCountintegerOptionalNumber of connectors at this stop (1-100)
chargingConnectorTypes("j1772" | "nacs" | "ccs" | "chademo" | "nema-14-50" | "nema-14-30" | "nema-tt-30" | "nema-5-15" | "nema-5-20")[]OptionalConnector types present, from: j1772, nacs, ccs, chademo, nema-14-50, nema-14-30, nema-tt-30, nema-5-15, nema-5-20
chargingNotesstringOptionalFree-form notes about charging (max 500 chars)
visitMonthstringOptionalYYYY-MM the report is for (optional, defaults to the current month)
session_idstringOptionalGroups this call with others in the same task.
agent_idstringOptionalDistinguishes this agent from others running in parallel.
intentstringOptionalWhy you are calling this tool.

submit_placeWrites

Submit a place

Submit a place that's missing from search into a moderation queue for a human to review. Does NOT create a live, searchable place - it returns a pending-submission id. Required: name, type (campground|hotel|motel|inn|rental|dispersed|park|trailhead|viewpoint|charger|restaurant|other), city, state. Optional: address, notes. If the place already exists or an identical submission is already pending, nothing is queued and the existing match is returned. Fails with a tool error if you already have 10 submissions awaiting moderation.

FieldTypeRequiredNotes
namestringRequiredPlace name
type"campground" | "hotel" | "motel" | "inn" | "rental" | "dispersed" | "park" | "trailhead" | "viewpoint" | "charger" | "restaurant" | "other"RequiredType of place: campground, hotel, motel, inn, rental, dispersed, park, trailhead, viewpoint, charger, restaurant, other
citystringRequiredCity
statestringRequiredState
addressstringOptionalStreet address (optional, admin-only informational metadata - never published as a precise coordinate)
notesstringOptionalFree-form notes for the reviewing admin (optional)
session_idstringOptionalGroups this call with others in the same task.
agent_idstringOptionalDistinguishes this agent from others running in parallel.
intentstringOptionalWhy you are calling this tool.

list_itinerary_itemsRead-only

List itinerary items

List the day-view itinerary items (activities, dining, sightseeing, notes, etc.) on one of your stops, ordered by day then order within day. Returns items: [] (not an error) for a zero-night stop, since day-view items only make sense on a stop with at least one overnight stay.

FieldTypeRequiredNotes
tripIdstringRequiredTrip id
waypointIdstringRequiredStop id
session_idstringOptionalGroups this call with others in the same task.
agent_idstringOptionalDistinguishes this agent from others running in parallel.
intentstringOptionalWhy you are calling this tool.

read_trip_itineraryRead-only

Read trip itinerary

Consolidated day-view itinerary across every top-level stop on a trip, in one call - each stop's basic info (name, city, state, nights, dates, canAddItems) alongside its items, avoiding one list_itinerary_items call per stop. Narrow with fromWaypointId/toWaypointId (both inclusive; omit either to run to the start/end of the trip) and/or upcomingOnly (stops not yet arrived at). A filter matching zero stops is a normal empty result (stops: [], itemCount: 0), never an error. When the trip has no startDate, dates can't be derived: all stops in range are returned and upcomingBasis is 'no-start-date' rather than filtering anything out. Sub-stops are not included here - use list_itinerary_items for those. Note: the arrived/upcoming boundary uses the server's UTC calendar day, not your local timezone, so it can be off by up to a day around midnight.

FieldTypeRequiredNotes
tripIdstringRequiredTrip id
fromWaypointIdstringOptionalOptional: only stops from this stop id onward (inclusive, by trip order). Omit to start from the first stop.
toWaypointIdstringOptionalOptional: only stops through this stop id (inclusive, by trip order). Omit to run through the last stop.
upcomingOnlybooleanOptionalOptional: only stops not yet arrived at (default false).
session_idstringOptionalGroups this call with others in the same task.
agent_idstringOptionalDistinguishes this agent from others running in parallel.
intentstringOptionalWhy you are calling this tool.

create_itinerary_itemWrites

Create itinerary item

Add a day-view itinerary item (activity, dining, sightseeing, etc.) to one of your stops. Rejects a zero-night stop - day-view items only make sense on a stop with at least one overnight stay - and rejects an invalid dayOffset/type/title with the app's own validation message text. Never accepts a coordinate.

FieldTypeRequiredNotes
tripIdstringRequiredTrip id
waypointIdstringRequiredStop id
dayOffsetintegerRequiredDay of the stay this item falls on, 0-indexed from arrival (0-365).
type"sightseeing" | "dining" | "activity" | "lodging" | "charging" | "transit" | "other"RequiredItem type: sightseeing, dining, activity, lodging, charging, transit, other
titlestringRequiredShort title for the item
descriptionstringOptionalOptional longer description
timeOfDaystringOptionalOptional free-form time, e.g. "9:00am" or "morning"
urlstringOptionalOptional link (e.g. a listing or reservation page)
session_idstringOptionalGroups this call with others in the same task.
agent_idstringOptionalDistinguishes this agent from others running in parallel.
intentstringOptionalWhy you are calling this tool.

update_itinerary_itemWrites

Update itinerary item

Edit a day-view itinerary item on one of your stops: title, description, url, timeOfDay, type, and/or dayOffset. waypointId names the stop the item is currently on - this tool never moves an item to a different stop (use move_itinerary_item for that). Only the fields you set are changed; omit a field to leave it unchanged, or pass null on description/url to explicitly clear it. Changing dayOffset moves the item to a different day on the SAME stop and leaves its order-within-day position as-is. Rejects an empty patch, and rejects an invalid value with the app's own validation message text.

FieldTypeRequiredNotes
tripIdstringRequiredTrip id
itemIdstringRequiredItem id
waypointIdstringRequiredStop the item is currently on
titlestringOptionalShort title for the item
descriptionstringOptionalOptional longer description
urlstringOptionalOptional link (e.g. a listing or reservation page)
timeOfDaystringOptionalOptional free-form time, e.g. "9:00am" or "morning"
type"sightseeing" | "dining" | "activity" | "lodging" | "charging" | "transit" | "other"OptionalItem type: sightseeing, dining, activity, lodging, charging, transit, other
dayOffsetintegerOptionalDay of the stay this item falls on, 0-indexed from arrival (0-365).
session_idstringOptionalGroups this call with others in the same task.
agent_idstringOptionalDistinguishes this agent from others running in parallel.
intentstringOptionalWhy you are calling this tool.

move_itinerary_itemWrites

Move itinerary item

Reassign a day-view itinerary item to a different stop on the SAME trip. waypointId is the DESTINATION stop - the source stop is read from the item itself. Optionally set dayOffset for its day on the new stop; omit it to keep the item's current dayOffset. Rejects moving an item to the stop it is already on (use update_itinerary_item to change its day instead), and rejects a zero-night source or destination stop. The item is appended to the end of the destination day, and its approval status and who added it are preserved verbatim - a move never approves a pending suggestion. There is no in-place move in the database: this recreates the item on the destination stop and deletes the original, so the moved item gets a NEW id (returned as item.id) and the old id is returned as previousItemId. If the recreate succeeds but the delete fails, the tool errors and a duplicate item is left behind for you to remove - it is never silently lost.

FieldTypeRequiredNotes
tripIdstringRequiredTrip id
itemIdstringRequiredItem id to move
waypointIdstringRequiredDestination stop id
dayOffsetintegerOptionalOptional: day of the stay on the destination stop (0-365). Defaults to the item's current dayOffset.
session_idstringOptionalGroups this call with others in the same task.
agent_idstringOptionalDistinguishes this agent from others running in parallel.
intentstringOptionalWhy you are calling this tool.

delete_itinerary_itemDestructive

Delete itinerary item

Remove a day-view itinerary item from one of your stops. The stop must still have at least one overnight stay for the delete to be allowed - the same rule the app enforces today, even for a delete.

FieldTypeRequiredNotes
tripIdstringRequiredTrip id
waypointIdstringRequiredStop id
itemIdstringRequiredItem id
session_idstringOptionalGroups this call with others in the same task.
agent_idstringOptionalDistinguishes this agent from others running in parallel.
intentstringOptionalWhy you are calling this tool.

request_waypoint_photo_uploadWrites

Request waypoint photo upload URL

Step 1 of 2 for attaching a photo to one of your own stops. Returns a one-time uploadUrl valid for 15 minutes: PUT the raw image bytes (jpeg/png/webp/heic, up to 10 MB) directly to that URL with a matching Content-Type header - do NOT send image data through this tool call or any other tool call. After the PUT succeeds, call finalize_waypoint_photo_upload with the returned uploadId to actually attach and store the photo. Call read_trip FIRST to get the trip's ordered stops (name, city/state, nights, public place coordinates, and the trip's startDate) - the stored photo has its embedded date/location metadata stripped as a privacy guarantee, so match the photo to the correct stop using its own metadata before you upload it. On an ambiguous match, confirm with the user rather than guessing - never invent a stop.

FieldTypeRequiredNotes
tripIdstringRequiredTrip id
waypointIdstringRequiredStop id
session_idstringOptionalGroups this call with others in the same task.
agent_idstringOptionalDistinguishes this agent from others running in parallel.
intentstringOptionalWhy you are calling this tool.

finalize_waypoint_photo_uploadWrites

Finalize waypoint photo upload

Step 2 of 2: call this AFTER you have successfully PUT the image bytes to the uploadUrl returned by request_waypoint_photo_upload. Attaches the uploaded photo to the stop. The photo is transcoded to WebP and stripped of metadata before storage, exactly like the in-app upload: images over 10 MB (decoded), an unrecognized image type, or a caption over 280 characters are all rejected. caption is optional and entirely your own words (e.g. from looking at the photo before it was stripped) - the server never generates one, and it doubles as the photo's accessible text description. uploadId expires 15 minutes after request_waypoint_photo_upload was called and can only be redeemed once.

FieldTypeRequiredNotes
tripIdstringRequiredTrip id
waypointIdstringRequiredStop id
uploadIdstringRequireduploadId returned by request_waypoint_photo_upload
captionstringOptionalOptional short caption (up to 280 characters), written by you from the photo itself - never generated by the server.
session_idstringOptionalGroups this call with others in the same task.
agent_idstringOptionalDistinguishes this agent from others running in parallel.
intentstringOptionalWhy you are calling this tool.