{"openapi":"3.1.0","info":{"title":"Dobby — staging-only train booking bot","version":"1.0.0","description":"HTTP API for Dobby (\"DotCom's Booking Bot → DBB → Dobby\"). All bookings hit the Eurostar **staging** environment with a test payment card — no real money, no real ticket, no production blast radius. Pair with the Streamable-HTTP MCP transport at `/mcp` for agent integrations that prefer MCP to OpenAPI.","contact":{"url":"https://github.com/diegoeil/eurostar-booking-bot"}},"servers":[{"url":"http://localhost:4242","description":"Public Dobby"}],"paths":{"/health":{"get":{"summary":"Health check","responses":{"200":{"description":"Server is up","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"name":{"type":"string"},"version":{"type":"string"},"uptimeSeconds":{"type":"integer"}}}}}}}}},"/api/booking":{"post":{"summary":"Create a staging booking","description":"Drives the full booking pipeline (journey search → cart → hold → checkout). Synchronous; 10–30 s typical.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["origin","destination","outboundDate","passengers","market"],"properties":{"origin":{"type":"string","description":"Origin station UIC code (e.g. `7015400` for London St Pancras)."},"destination":{"type":"string","description":"Destination station UIC code."},"outboundDate":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"ISO date YYYY-MM-DD."},"inboundDate":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"ISO date YYYY-MM-DD. Provide for a return journey."},"passengers":{"type":"object","required":["adults","children","seniors","youths","infants","adultsWheelchair","childrenWheelchair","wheelchairCompanions","guideDogs"],"properties":{"adults":{"type":"integer","minimum":0,"maximum":9},"children":{"type":"integer","minimum":0,"maximum":9},"seniors":{"type":"integer","minimum":0,"maximum":9},"youths":{"type":"integer","minimum":0,"maximum":9},"infants":{"type":"integer","minimum":0,"maximum":9},"adultsWheelchair":{"type":"integer","minimum":0,"maximum":1,"description":"Use INSTEAD of `adults` for a wheelchair adult booking."},"childrenWheelchair":{"type":"integer","minimum":0,"maximum":1},"wheelchairCompanions":{"type":"integer","minimum":0,"maximum":1,"description":"Only valid alongside `adultsWheelchair` or `childrenWheelchair`."},"guideDogs":{"type":"integer","minimum":0,"maximum":9}}},"market":{"type":"string","enum":["uk-en","fr-fr","be-fr","be-en","be-nl","de-de","nl-nl","en-US","en-RW"]},"currency":{"type":"string","enum":["GBP","EUR","USD"]},"language":{"type":"string","enum":["en","fr","de","nl"]},"outClass":{"description":"Preferred outbound class of service. Pass a single string (e.g. `\"STANDARD\"`) or an array of any-of values (e.g. `[\"STANDARD\", \"PLUS\"]`). Omit for cheapest.","oneOf":[{"type":"string","enum":["STANDARD","PLUS","PREMIER"]},{"type":"array","minItems":1,"items":{"type":"string","enum":["STANDARD","PLUS","PREMIER"]}}]},"rtnClass":{"description":"Preferred return class of service. Pass a single string (e.g. `\"STANDARD\"`) or an array of any-of values (e.g. `[\"STANDARD\", \"PLUS\"]`). Omit for cheapest.","oneOf":[{"type":"string","enum":["STANDARD","PLUS","PREMIER"]},{"type":"array","minItems":1,"items":{"type":"string","enum":["STANDARD","PLUS","PREMIER"]}}]},"outTrain":{"type":"string"},"rtnTrain":{"type":"string"},"outTime":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$"},"rtnTime":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$"},"outNth":{"type":"integer","description":"0 = first journey of the day, -1 = last, 1 = second, etc."},"rtnNth":{"type":"integer"},"api":{"type":"boolean","description":"Run Advanced Passenger Information after the booking."},"snap":{"type":"boolean","description":"Snap-app inventory: LASTMIN, direct trains, STANDARD only."},"unallocated":{"type":"boolean","description":"Unallocated inventory: RED_US, direct trains, UNASSIGNED class."},"productFamily":{"type":"string"},"shopperEmail":{"type":"string","description":"Override shopper email. Templates: {carrier}/{scenario}/{market}/{pax}/{od}."},"cid":{"type":"string","description":"CID template. Placeholders: {carrier}/{scenario}/{datetime}/{pax}/{od}/{i}/{market}."}}}}}},"responses":{"200":{"description":"Booking created","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"bookingReference":{"type":"string"},"lastName":{"type":"string"},"cartId":{"type":"string"},"error":{"type":"string"},"links":{"type":"object","properties":{"myb":{"type":"string"},"voyager":{"type":"string"}}},"timings":{"type":"object","properties":{"search":{"type":"number"},"createCart":{"type":"number"},"holdCart":{"type":"number"},"checkout":{"type":"number"}}},"selectedJourney":{"type":"object","properties":{"outbound":{"type":"object","properties":{"legs":{"type":"array","items":{"type":"object","properties":{"origin":{"type":"string"},"destination":{"type":"string"},"departureDate":{"type":"string"},"departureTime":{"type":"string"},"arrivalTime":{"type":"string"},"trainNumber":{"type":"string"},"classOfService":{"type":"string"}}}},"totalPrice":{"type":"number"}}},"inbound":{"type":"object","properties":{"legs":{"type":"array","items":{"type":"object","properties":{"origin":{"type":"string"},"destination":{"type":"string"},"departureDate":{"type":"string"},"departureTime":{"type":"string"},"arrivalTime":{"type":"string"},"trainNumber":{"type":"string"},"classOfService":{"type":"string"}}}},"totalPrice":{"type":"number"}}}}}}}}}},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"details":{"type":"object","description":"zod-format validation details (when applicable)"}}}}}},"500":{"description":"Pipeline error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"details":{"type":"object","description":"zod-format validation details (when applicable)"}}}}}}}}},"/api/prompt":{"post":{"summary":"Create a booking from a natural-language prompt","description":"LLM-translates a free-text request (e.g. \"book wheelchair to amsterdam next saturday\") into a BookingRequest, then runs the full booking pipeline. Response is the same as `/api/booking` plus a `summary` echo, optional `warnings`, and an `llm` block with provider/model/cost.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["prompt"],"properties":{"prompt":{"type":"string","description":"The natural-language booking request."}}}}}},"responses":{"200":{"description":"Booking created","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"bookingReference":{"type":"string"},"lastName":{"type":"string"},"cartId":{"type":"string"},"error":{"type":"string"},"links":{"type":"object","properties":{"myb":{"type":"string"},"voyager":{"type":"string"}}},"timings":{"type":"object","properties":{"search":{"type":"number"},"createCart":{"type":"number"},"holdCart":{"type":"number"},"checkout":{"type":"number"}}},"selectedJourney":{"type":"object","properties":{"outbound":{"type":"object","properties":{"legs":{"type":"array","items":{"type":"object","properties":{"origin":{"type":"string"},"destination":{"type":"string"},"departureDate":{"type":"string"},"departureTime":{"type":"string"},"arrivalTime":{"type":"string"},"trainNumber":{"type":"string"},"classOfService":{"type":"string"}}}},"totalPrice":{"type":"number"}}},"inbound":{"type":"object","properties":{"legs":{"type":"array","items":{"type":"object","properties":{"origin":{"type":"string"},"destination":{"type":"string"},"departureDate":{"type":"string"},"departureTime":{"type":"string"},"arrivalTime":{"type":"string"},"trainNumber":{"type":"string"},"classOfService":{"type":"string"}}}},"totalPrice":{"type":"number"}}}}}}}}}},"400":{"description":"Missing or empty prompt","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"details":{"type":"object","description":"zod-format validation details (when applicable)"}}}}}},"422":{"description":"LLM disabled, daily budget reached, or prompt could not be parsed into a valid BookingRequest","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"details":{"type":"object","description":"zod-format validation details (when applicable)"}}}}}},"500":{"description":"Pipeline error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"details":{"type":"object","description":"zod-format validation details (when applicable)"}}}}}}}}},"/api/search-link":{"post":{"summary":"Build an eurostar.com search URL","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["origin","destination","outboundDate","passengers","market"],"properties":{"origin":{"type":"string","description":"Origin station UIC code (e.g. `7015400` for London St Pancras)."},"destination":{"type":"string","description":"Destination station UIC code."},"outboundDate":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"ISO date YYYY-MM-DD."},"inboundDate":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"ISO date YYYY-MM-DD. Provide for a return journey."},"passengers":{"type":"object","required":["adults","children","seniors","youths","infants","adultsWheelchair","childrenWheelchair","wheelchairCompanions","guideDogs"],"properties":{"adults":{"type":"integer","minimum":0,"maximum":9},"children":{"type":"integer","minimum":0,"maximum":9},"seniors":{"type":"integer","minimum":0,"maximum":9},"youths":{"type":"integer","minimum":0,"maximum":9},"infants":{"type":"integer","minimum":0,"maximum":9},"adultsWheelchair":{"type":"integer","minimum":0,"maximum":1,"description":"Use INSTEAD of `adults` for a wheelchair adult booking."},"childrenWheelchair":{"type":"integer","minimum":0,"maximum":1},"wheelchairCompanions":{"type":"integer","minimum":0,"maximum":1,"description":"Only valid alongside `adultsWheelchair` or `childrenWheelchair`."},"guideDogs":{"type":"integer","minimum":0,"maximum":9}}},"market":{"type":"string","enum":["uk-en","fr-fr","be-fr","be-en","be-nl","de-de","nl-nl","en-US","en-RW"]},"currency":{"type":"string","enum":["GBP","EUR","USD"]},"language":{"type":"string","enum":["en","fr","de","nl"]},"outClass":{"description":"Preferred outbound class of service. Pass a single string (e.g. `\"STANDARD\"`) or an array of any-of values (e.g. `[\"STANDARD\", \"PLUS\"]`). Omit for cheapest.","oneOf":[{"type":"string","enum":["STANDARD","PLUS","PREMIER"]},{"type":"array","minItems":1,"items":{"type":"string","enum":["STANDARD","PLUS","PREMIER"]}}]},"rtnClass":{"description":"Preferred return class of service. Pass a single string (e.g. `\"STANDARD\"`) or an array of any-of values (e.g. `[\"STANDARD\", \"PLUS\"]`). Omit for cheapest.","oneOf":[{"type":"string","enum":["STANDARD","PLUS","PREMIER"]},{"type":"array","minItems":1,"items":{"type":"string","enum":["STANDARD","PLUS","PREMIER"]}}]},"outTrain":{"type":"string"},"rtnTrain":{"type":"string"},"outTime":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$"},"rtnTime":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$"},"outNth":{"type":"integer","description":"0 = first journey of the day, -1 = last, 1 = second, etc."},"rtnNth":{"type":"integer"},"api":{"type":"boolean","description":"Run Advanced Passenger Information after the booking."},"snap":{"type":"boolean","description":"Snap-app inventory: LASTMIN, direct trains, STANDARD only."},"unallocated":{"type":"boolean","description":"Unallocated inventory: RED_US, direct trains, UNASSIGNED class."},"productFamily":{"type":"string"},"shopperEmail":{"type":"string","description":"Override shopper email. Templates: {carrier}/{scenario}/{market}/{pax}/{od}."},"cid":{"type":"string","description":"CID template. Placeholders: {carrier}/{scenario}/{datetime}/{pax}/{od}/{i}/{market}."}}}}}},"responses":{"200":{"description":"Search URL built","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri"}},"required":["url"]}}}},"400":{"description":"Invalid body","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"details":{"type":"object","description":"zod-format validation details (when applicable)"}}}}}},"500":{"description":"Generation failed","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"details":{"type":"object","description":"zod-format validation details (when applicable)"}}}}}}}}}}}