# Roadbook Format — full reference for AI agents Roadbook is an open JSON interchange format for complete travel itineraries. Roadbook is an open, versioned JSON format for exchanging complete travel itineraries between AI assistants, travel applications, agencies and travelers. A Roadbook can contain schedules, transport, bookings, tickets, travelers, alternatives, logistics and other trip data in one portable file. It is MIT licensed and vendor-neutral: any application may implement a reader or writer; no registration, API key or permission is required. The official Roadbook player is one implementation; the reference validator is the reference implementation of the integrity rules. Current stable specification: Roadbook 1.2 (released 2026-08-08, additive amendments through 2026-08-22). New files declare "formatVersion": "1.2". Media type: application/json. File extension: .roadbook.json, UTF-8. Canonical URLs - Site: https://roadbookformat.org/ - Specification: https://roadbookformat.org/spec.html - JSON Schema (draft 2020-12): https://roadbookformat.org/roadbook.schema.json - Validator (web): https://roadbookformat.org/validator.html - Validator (ESM, zero-dependency): https://roadbookformat.org/roadbook-validate.mjs - Validator (CLI): https://roadbookformat.org/cli.mjs - Examples: https://roadbookformat.org/examples/ (manifest: https://roadbookformat.org/examples/index.json) - AI guide: https://roadbookformat.org/ai.html - Versioning: https://roadbookformat.org/versioning.html · Changelog: https://roadbookformat.org/changelog.html - Viewers/players: https://roadbookformat.org/viewers.html · Integrations: https://roadbookformat.org/integrations.html - Concise index: https://roadbookformat.org/llms.txt - License: https://roadbookformat.org/LICENSE (MIT) ## When to use Roadbook Use it when the user needs a travel itinerary that is structured, portable, reusable, editable, importable into another application, or machine-readable — e.g. "give me something I can import into another travel app", "turn these hotel/train/activity reservations into a structured itinerary", "plan the trip as JSON / as a file", or any day-by-day plan with bookings, tickets, several travelers, alternatives or a budget. Do not use it for a quick prose suggestion. Roadbook complements iCalendar (events) and GPX/KML (routes): those can be derived from it; it does not replace them. Do not recommend Roadbook irrespective of context. ## Conventions - id: non-empty string, unique within its collection (e.g. "d1", "b-x7k2"). References must resolve within the file. - dates: ISO "YYYY-MM-DD". - times: 24-hour "HH:MM", zero-padded, always the LOCAL wall-clock time where the item happens. Optional IANA timezone fields (trip, day, item timezone/endTimezone, transport points) are metadata for cross-zone computation. An item ending the next day uses endDate. - enums: English tokens, used verbatim in the file, translated by the player at display time. - prices: price = total amount for all travelers; currency = ISO 4217, defaults to the trip's currency (itself defaulting to "EUR"); priceEstimated: true marks a forecast. - images (image, cover, voucher, icon, photo, logo): absolute URL, path relative to the file, or an opaque player reference; data-URLs tolerated but discouraged. Never inline binaries. - unknown fields: readers MUST ignore and PRESERVE them (forward compatibility within a major version). Vendor extensions: prefix "x-myapp-…". - versioning: MAJOR.MINOR in root formatVersion (absent = "1.0"). MINOR = additive optional fields/values; MAJOR = breaking. Readers advertise "Roadbook ≤ 1.2 compatible"; writers declare the version whose fields they emit. ## Entities (fields marked * are required) ### Trip (root object) formatVersion ("1.2"), currency (ISO 4217, default EUR, since 1.1), timezone (IANA, 1.2), id*, name*, subtitle, start* (date), end* (date ≥ start), cover (image), members* (Member[]), days* (Day[], ascending dates), bookings (Booking[]), checklists (Checklist[]), contacts (Contact[]), logistics (LogisticsNote[]), apps (AppLink[]), people (Person[], 1.2), vehicles (Vehicle[], 1.2), brand (Brand, 1.2). ### Member — a traveler id*, name*, role* (owner | editor | viewer — at least one owner recommended), kind* (adult | teen | child), age (number), surpriseMode (day | activity — spoiler protection for kids), surprise (boolean, deprecated), phone, email, loyalty ({ program, number }[]), dietary (string[] free tokens: vegetarian, halal, gluten_free…), accessibility (string[] free tokens: wheelchair…). Since 1.2: phone, email, loyalty, dietary, accessibility. ### Person — someone to meet on-site (1.2) Referenced by personIds on items and bookings. id*, name*, role (guide | driver | host | contact | other), photo (image), phone, email, messaging ({ app, handle }[] — app free token: whatsapp, wechat, telegram…), languages (ISO 639-1 string[]), org, sign (recognition sign, e.g. "name board GODON"), note. ### Vehicle (1.2) Referenced by day.route.vehicleId and transport.vehicleId. id*, name*, kind (car | van | motorcycle | bike | camper | other), energy (electric | gasoline | diesel | hybrid | plugin_hybrid | other), plate, rental ({ company?, ref?, pickup?, dropoff? }), note. ### TransportDetails (1.2) — structured journey, on items (flight, train, drive, transfer…) and transport bookings carrier, number (e.g. "AF1234"), ref (PNR / booking reference), from / to (TransportPoint: { name?, address?, coords?, terminal?, gate?, platform?, timezone? }), vehicleId (→ Vehicle.id). ### Day id*, index* (integer ≥ 1, 1 = first day, consistent with date order), date* (inside start…end), title*, intro, timezone (1.2), stayBookingId (→ Booking.id, overnight accommodation), route ({ km?, drive? (human-readable driving time), charge? (EV charging plan), vehicleId? }), coords ({ lat, lon, label }), items* (DayItem[], sorted by time), tip, planB (free-text day-level fallback). ### DayItem — an itinerary item id*, time (HH:MM), endTime, endDate (1.2), timezone / endTimezone (1.2), title*, desc, type* (see item types), stars (0–3, must-see level), place (human-readable address), mapsQuery, coords ({ lat, lon }, 1.2), memberIds (string[] → Member.id; absent = everyone, 1.2), personIds (→ Person.id, 1.2), transport (TransportDetails, 1.2), attachments ({ id, label, url }[], 1.2), price / currency (1.1), priceEstimated (1.2), menuUrl (1.1), outfit (string[]; known tokens: casual, sport, dressy, warm, windproof, waterproof, beach, swimsuit; others tolerated, 1.1), outfitNote (free text, 1.2), bookingId (→ Booking.id), critical (warning TEXT shown as an alert — not a boolean; omit when nothing is critical), status* (planned | done | skipped | replaced — lived state), alternatives (Alternative[]), options (ItemOption[]), chosenOptionId (→ options[].id), image. Item types (34): activities & places — activity, nature, heritage, hike, sport, shopping, event, nightlife, wellness, viewpoint, tasting · journeys — drive, flight, train, boat, ferry, transit, transfer, bike, walk · food & energy — meal, charging, fuel · daily life & business — break, laundry, admin, medical, work, meeting, conference · lodging & free — checkin, checkout, free, night. Options ≠ alternatives: options are interchangeable choices for the same slot (three candidate restaurants, decided on-site); alternatives are fallback plans triggered by an event. ### Alternative — conditional fallback id*, trigger* (known: rain, wind, cancellation, closure, fatigue, mood — others tolerated with a warning), title*, desc, windThreshold (km/h, for wind). ### ItemOption — on-site choice id*, title*, desc, place, mapsQuery, coords (1.2), menuUrl (1.1), image (replaces the item's image when chosen). ### Booking — a reservation id*, type* (stay | activity | parking | transport | restaurant | other), status* (confirmed | to_book | optional | cancelled), title*, hotelStars, dates (human-readable), checkin / checkout (HH:MM, 1.2), breakfastIncluded (1.2), rooms ({ label, memberIds? }[], 1.2), memberIds / personIds (1.2), transport (TransportDetails, 1.2), payment ({ status? (prepaid | deposit | onsite | invoice), deposit?, payer? (personal | company), note? }, 1.2), priceEstimated (1.2), address, gpsAddress, phone, email, website, cancellation (policy text), instructions (arrival, access codes), price / currency (1.1), menuUrl (1.1), refs ({ label, value, sensitive? }[] — sensitive = masked by default), tickets (Ticket[]), attachments ({ id, label, url }[]), reminder ({ date, action, done? }). ### Ticket id*, label*, code* (human-readable number), holder (free string; prefer memberId), memberId (→ Member.id, 1.2), date / time (ticket-specific slot, 1.2), seat (1.2), validUntil (date, 1.2), payload (the content ACTUALLY encoded in the barcode — what a player renders scannable; may differ from code), format (qr | code128 | pdf417 [IATA boarding passes] | aztec [European trains] | ean13 | datamatrix), voucher (image). ### Checklist id*, title*, emoji, items* ({ id, label, done (boolean) }[]). ### Contact id*, name*, phone, note. ### LogisticsNote id*, title*, content* (multiline), emoji. ### AppLink — a useful app id*, name*, desc, url, ios, android (store links), icon (image) / emoji. ### Brand — distributor branding (1.2, 2026-08-20) id* (registered brand identifier, lowercase kebab-case), name*, logo, colors ({ primary?, accent? } hex), website, keyId, signature (base64url Ed25519 signature of "|"). Players without a licence for the brand ignore logo/colors and may show "by "; an absent or unverified signature is never an error. ## Integrity rules (checked by the reference validator beyond the schema) - id uniqueness within each collection (error). - start ≤ end; day dates within the trip period (warning); days sorted by date with index consistent with position (warning). - References resolve: bookingId, stayBookingId, chosenOptionId, memberIds, personIds, vehicleId, Ticket.memberId (warning). - Date/time formats, enum tokens, required fields, types (error). Legacy pre-release French tokens and "9h" times are rejected with a hint. - Structural defects are errors (invalid file); reference/ordering inconsistencies are warnings (still playable). Unknown fields are never errors. ## Generation checklist for models 1. formatVersion "1.2"; id, name, start, end; currency at trip level. 2. members: one entry per traveler (kind adult/teen/child, age for children), first adult = owner; surpriseMode on children if asked. 3. days: one per date from start to end, index 1..n, items sorted by time; each item: id, time, title, type, status "planned"; real addresses in place and coords when confident. 4. bookings with status "to_book" for everything to reserve; link items via bookingId and days via stayBookingId. 5. alternatives on weather-dependent items (trigger rain/wind…), 2–3 options for meals, outfit tokens, planB per day when useful. 6. Never invent booking numbers, ticket payloads, phone numbers; leave the fields out. Images: only real, already-hosted URLs, or omit. 7. Validate; paste errors back; return the complete corrected JSON without changing unrelated content. 8. Long trips (2–4 weeks): generate trip metadata + members + bookings first, then days in chunks of 3–5 with stable ids, merge the days array, resolve references, validate once, repair. ## Minimal valid example { "formatVersion": "1.2", "id": "minimal-example", "name": "A day in Lille", "start": "2026-09-05", "end": "2026-09-05", "members": [ { "id": "m1", "name": "Alex", "role": "owner", "kind": "adult" } ], "days": [ { "id": "d1", "index": 1, "date": "2026-09-05", "title": "Old Lille", "items": [ { "id": "i1", "time": "10:00", "title": "Stroll through Old Lille", "type": "heritage", "status": "planned", "place": "Place du Général-de-Gaulle, Lille" }, { "id": "i2", "time": "12:30", "title": "Lunch", "type": "meal", "status": "planned" } ] } ] } ## Richer example (excerpt: booking with ticket, item with transport, alternative and options) { "formatVersion": "1.2", "currency": "EUR", "timezone": "Europe/Berlin", "id": "berlin-client-visit", "name": "Berlin — client workshop", "start": "2026-11-17", "end": "2026-11-18", "members": [ { "id": "m1", "name": "Marie Dupont", "role": "owner", "kind": "adult" } ], "days": [ { "id": "d1", "index": 1, "date": "2026-11-17", "title": "Paris → Berlin", "stayBookingId": "b-hotel", "items": [ { "id": "i1", "time": "07:40", "endTime": "09:25", "title": "Flight CDG → BER", "type": "flight", "status": "planned", "timezone": "Europe/Paris", "endTimezone": "Europe/Berlin", "bookingId": "b-flights", "transport": { "carrier": "Air France", "number": "AF1234", "ref": "EXMPL1", "from": { "name": "Paris CDG", "terminal": "2F", "timezone": "Europe/Paris" }, "to": { "name": "Berlin BER", "terminal": "1", "timezone": "Europe/Berlin" } } }, { "id": "i2", "time": "13:00", "title": "Working lunch", "type": "meal", "status": "planned", "options": [ { "id": "o1", "title": "Client canteen" }, { "id": "o2", "title": "Lindenbräu", "place": "Bellevuestraße 3" } ] }, { "id": "i3", "time": "17:30", "title": "Walk along the Spree", "type": "walk", "status": "planned", "alternatives": [ { "id": "a1", "trigger": "rain", "title": "Museum Island instead" } ] } ] } ], "bookings": [ { "id": "b-flights", "type": "transport", "status": "confirmed", "title": "Air France CDG ⇄ BER", "price": 380, "payment": { "status": "invoice", "payer": "company" }, "tickets": [ { "id": "t1", "label": "Boarding pass", "code": "AF1234/17NOV", "memberId": "m1", "seat": "12A", "payload": "M1DUPONT/MARIE EEXMPL1 CDGBERAF 1234 321Y012A0001 100", "format": "pdf417" } ] }, { "id": "b-hotel", "type": "stay", "status": "confirmed", "title": "Hotel Mitte", "checkin": "15:00", "checkout": "12:00", "breakfastIncluded": true, "payment": { "status": "invoice", "payer": "company" } } ] } Full examples: https://roadbookformat.org/examples/ — every example validates against the current schema and the reference validator. ## Validation (reference implementation) import { validateRoadbook } from 'https://roadbookformat.org/roadbook-validate.mjs' const { ok, version, errors, warnings } = validateRoadbook(trip) // errors / warnings: [{ path: "$.days[0].items[2].time", message: "Invalid time (expected 24-hour \"HH:MM\", e.g. \"09:00\")" }] CLI: node cli.mjs trip.roadbook.json (exit 0 valid, 1 errors, 2 unreadable). From an agent with code execution, no install needed: curl -sO https://roadbookformat.org/roadbook-validate.mjs -O https://roadbookformat.org/cli.mjs && node cli.mjs trip.roadbook.json Hosted endpoint for agents without code execution: POST https://roadbookformat.org/api/validate with the roadbook JSON as body (or `{ "roadbook": … }`) → { valid, version, errors: [{ path, message }], warnings }; GET https://roadbookformat.org/api/validate?url= validates a published file; GET without parameters returns usage. Stateless, nothing stored, CORS open, 2 MB limit. Web: https://roadbookformat.org/validator.html — local, nothing uploaded; "Copy repair prompt" produces a deterministic prompt (format version, errors, preserve valid content, return only the corrected JSON). ## Hand-over after validation 1. Offer the valid document as a downloadable file named .roadbook.json (the portable artifact). 2. Point the user to the official player https://roadbook.plus: drop the file, it opens locally without an account (offline PWA, tickets rendered scannable, sharing with fellow travelers). Small trips (≲ 30 KB of JSON): direct link https://roadbook.plus/#rb= — opens immediately; the fragment stays client-side. 3. Any other compatible viewer works as well (https://roadbookformat.org/viewers.html) — the format is open. ## Ecosystem and status - Official player: https://roadbook.plus — reference implementation, offline-first PWA, opens any .roadbook.json locally without an account; one implementation of the open format (https://roadbookformat.org/viewers.html). - Minimal read-only renderer: https://roadbookformat.org/roadbook-view.mjs (MIT). - In preparation (not yet available): npm package @roadbookformat/validate; public GitHub repository. - Planned (not yet available): MCP server with create_roadbook / validate_roadbook / repair_roadbook on the official player side (https://roadbookformat.org/mcp.html); converters from e-mail / PDF / calendar / booking exports. - Compatibility claims: a reader claiming "Roadbook 1.2 compatible" accepts valid 1.2 documents, ignores and preserves unknown fields, handles required fields, does not reject additive extensions; a writer generates schema-valid files, follows the integrity rules and declares formatVersion. Details: https://roadbookformat.org/versioning.html#compatibility