{"openapi":"3.1.0","info":{"title":"legtolegcruises.com public API","version":"1.1.0","description":"Back-to-back Royal Caribbean cruises: consecutive sailings where the next one departs the port the last one ends at, on the day it arrives. Most start and end in one home port; a trip that includes a one-way sailing can end elsewhere, and says so (endPort, endsElsewhere). Free, read-only, no key, CORS open. Inventory is refreshed on a schedule, not live. Every response carries `dataAsOf` and `dataAgeHours`; check them before presenting a fare as current. Not affiliated with Royal Caribbean International.","license":{"name":"Free to use and cite, with a link back to the page named in each result."},"contact":{"url":"https://legtolegcruises.com/for-ai"}},"servers":[{"url":"https://legtolegcruises.com"}],"paths":{"/api/public/back-to-backs":{"get":{"operationId":"search_back_to_backs","summary":"Search back-to-back cruises","description":"Find runs of consecutive Royal Caribbean sailings, where each one leaves the port the last one ends at, on the day it arrives. Most runs start and end in the same home port; one that includes a one-way sailing (a transatlantic, Alaska northbound) can end somewhere else, and each result says where (endPort, endsElsewhere, and each leg's from and to). Never describe a trip as returning home unless endsElsewhere is false. A back-to-back is NOT limited to two sailings: the search links as many legs as the schedule allows, and trips of ten, twelve or fifteen legs on a single ship exist and are the thing this site is best at finding. It defaults to two legs, so pass minLegs and maxLegs to go longer. Returns dates, ships, nights, every itinerary in the run, and a lead-in fare per guest (the price for two guests sharing a cabin). Use sameShip=true for trips that stay on one ship the whole way. That means no disembarking between legs; it does not guarantee the same stateroom, which the guest has to request when booking. Use sort for the order (cheapest, mostExpensive, perNight, perNightHigh, longest, shortest, mostLegs, fewestLegs, soonest, latest; Best match by default, as the finder lists) and pass nextCursor back as cursor for the next page. When matchedDisplay ends in \"+\", counting stopped at a floor; the trips listed are still the true first ones in that order. Pass guests for a group: a cabin holds at most 4, so 5 to 8 guests are priced in two cabins, the bigger first (5 is 3 and 2, 6 is 3 and 3, 7 is 4 and 3, 8 is 4 and 4), interior on every cruise, the way the finder on the site prices them. The answer then says so in `party` (guests, cabins and a plain sentence to read back), each trip carries groupTotal (the whole group, every cruise, taxes and port fees in) and fromPerGuest (that total divided by the guests), and each leg the price of each cabin; maxPrice is per guest of the whole group. 4 guests or fewer is one cabin and lists exactly what the search without guests lists.","parameters":[{"name":"port","in":"query","required":false,"description":"Home port code, e.g. MIA, FLL, PCN, or its name or a common alias (Los Angeles, LA, NOLA, Houston). Omit to search every port.","schema":{"type":"string"}},{"name":"minLegs","in":"query","required":false,"description":"Fewest sailings in the run. Default 2, and there is no practical ceiling: long back-to-backs are the product, so asking for fifteen legs gets fifteen legs. Raise this to find long trips; a ten-leg run out of Miami is an ordinary result, not an exotic one.","schema":{"type":"number"}},{"name":"maxLegs","in":"query","required":false,"description":"Most sailings in the run. Defaults to minLegs. Searching a wide leg range across every port is expensive, so name a port when asking for long trips.","schema":{"type":"number"}},{"name":"from","in":"query","required":false,"description":"The trip leaves on or after this day (its first cruise), YYYY-MM-DD. The same as the finder's \"On or after\".","schema":{"type":"string"}},{"name":"to","in":"query","required":false,"description":"The trip leaves on or before this day (its first cruise; later legs may sail after it), YYYY-MM-DD. The same as the finder's \"On or before\".","schema":{"type":"string"}},{"name":"minNights","in":"query","required":false,"description":"Minimum combined nights across the whole run.","schema":{"type":"number"}},{"name":"maxNights","in":"query","required":false,"description":"Maximum combined nights across the whole run.","schema":{"type":"number"}},{"name":"sameShip","in":"query","required":false,"description":"Only trips staying on one ship throughout.","schema":{"type":"boolean"}},{"name":"maxPrice","in":"query","required":false,"description":"Maximum lead-in fare per guest (the price for two guests sharing a cabin), USD, all legs combined, taxes included. Trips without a published fare for every leg are left out when this is set, and counted in unpricedExcluded.","schema":{"type":"number"}},{"name":"guests","in":"query","required":false,"description":"How many guests are going, 1 to 8. A cabin holds at most 4, so 5 to 8 are priced in two cabins (the answer says so in party, and every trip carries groupTotal); 4 or fewer changes nothing, as every guest pays the same per guest fare. More than 8 is priced for 8 and said.","schema":{"type":"number"}},{"name":"ship","in":"query","required":false,"description":"Restrict to one ship. Accepts a Royal Caribbean ship code (IC, FR, AN) or a name (\"Icon of the Seas\"). Call list_ships for the codes.","schema":{"type":"string"}},{"name":"sort","in":"query","required":false,"description":"Order of the results, over the WHOLE answer: when omitted, Best match, the same trips in the same order as the finder on the site (trips with a published fare first); soonest (departure date alone, a trip without a price keeps its place and is marked with fareNote), latest (latest departure), cheapest (lowest fare per guest), mostExpensive (highest fare per guest), perNight (lowest fare per night), perNightHigh (highest fare per night), longest (most nights), shortest (fewest nights), mostLegs, fewestLegs. The first page is the true first trips in this order even when the count stops at a floor (matchedDisplay \"20,000+\").","schema":{"type":"string"}},{"name":"cursor","in":"query","required":false,"description":"The nextCursor from the previous page of this SAME search (same filters and sort), to get the next page. Omit for the first page.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"How many to return, 1-100. Default 25.","schema":{"type":"number"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/api/public/ports":{"get":{"operationId":"list_home_ports","summary":"List home ports","description":"Every home port with cached sailings, with how many back-to-backs each one has, how many are same-ship, the nights range and the lead-in fare. Call this first when the user has not named a port, or to check a port code before searching.","parameters":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/api/public/ships":{"get":{"operationId":"list_ships","summary":"List Royal Caribbean ships","description":"The Royal Caribbean fleet, with class, year built, guest capacity, gross tonnage, and how many sailings that have not yet departed this site tracks for each ship. A ship with 0 such sailings has none you can still book from the home ports we cover (all its sailings may have left, or it may sail from ports outside our cache); that does not mean the ship is out of service.","parameters":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/api/public/price-history":{"get":{"operationId":"get_price_history","summary":"Fare history for one sailing","description":"What one sailing has cost each day this site has tracked it, and whether today's fare is low, normal or high AGAINST ITS OWN HISTORY. Use this to answer \"is this a good price?\". A fare alone cannot answer that. Returns low, high, average, a percentile (the share of tracked days that were cheaper than today; 10 means today beats 90% of them), the 7-day change, and the number of observations behind it. No verdict is given below 7 days of history: report the numbers and say the history is young rather than guessing. When the cabin is not on sale today, current is null and there is no verdict; lastSeenPrice and lastSeen say what it last cost and when. Get a sailingId from the legs returned by search_back_to_backs.","parameters":[{"name":"sailingId","in":"query","required":true,"description":"The sailing id, from a leg in search_back_to_backs results.","schema":{"type":"string"}},{"name":"cabin","in":"query","required":false,"description":"interior (default), oceanview, balcony or suite.","schema":{"type":"string"}},{"name":"days","in":"query","required":false,"description":"How far back to look, 1-1095. Default 365.","schema":{"type":"number"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/api/public/price-drops":{"get":{"operationId":"find_price_drops","summary":"Sailings currently below their own average","description":"Sailings on sale now whose current fare is furthest below their OWN tracked average, cheapest relative to themselves first. Compared per sailing rather than across the fleet, so a short cheap cruise does not permanently outrank a long expensive one. Only sailings with at least 7 days of history are considered, and never one that has sailed or is sold out in the cabin asked for. Use for \"what is a good deal right now\".","parameters":[{"name":"port","in":"query","required":false,"description":"Restrict to one home port: its code, e.g. MIA, or its name or a common alias.","schema":{"type":"string"}},{"name":"cabin","in":"query","required":false,"description":"interior (default), oceanview, balcony or suite.","schema":{"type":"string"}},{"name":"days","in":"query","required":false,"description":"Window for the average, 7-365. Default 90.","schema":{"type":"number"}},{"name":"limit","in":"query","required":false,"description":"How many to return, 1-100. Default 20.","schema":{"type":"number"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/api/public/search":{"get":{"operationId":"search_in_plain_language","summary":"Search back-to-backs by describing the trip","description":"Describe the trip the way a person would (\"a 40 day back-to-back starting in Los Angeles to Mexico\", \"two weeks out of Miami on one ship under $2,000\") and get back the structured filters that were understood alongside the matching sailings. Use this when the user has described a trip rather than named specific filter values, or when you are not sure which port code or region a place maps to. The response includes `understood` (the filters extracted), `interpreted` (those filters in plain English), and `assumptions` (defaults applied that the user did not state). Read them back to the user before presenting results, because a misread constraint is the most common way this goes wrong. The trips, their order and their count are the ones the site's own finder lists for the same sentence (2 to 4 legs unless the sentence names a number; a month or dates mean when the trip leaves, its first cruise; a region or ship applies to every leg), and `searchUrl` opens that same search on the site. Only when the sentence asks to change ports between cruises (\"switch ports\", \"Fort Lauderdale then Miami\"), a trip may also get off in Miami or Fort Lauderdale and board the next ship in the other port the same day: such a trip says so in `portChanges` and `changeNote` (read it back), its price is the cruises only (the ride between the ports is not in it), and it has no trip page. If nothing matches, the response explains which constraint emptied it and what relaxing each one would return, and offers the closest real trips. Every result is a real back-to-back built from cached sailings; nothing here is generated. A group of 5 to 8 (\"for 6 people\", \"a family of 7\") is priced in two cabins, the bigger first, the way the finder on the site prices it: the answer says so in `party` (guests, cabins and a plain sentence to read back), each trip carries groupTotal (the whole group, every cruise, taxes and port fees in) and fromPerGuest (that total divided by the guests), and each leg the price of each cabin.","parameters":[{"name":"q","in":"query","required":true,"description":"The trip, described in plain language. Up to 400 characters.","schema":{"type":"string"}},{"name":"cursor","in":"query","required":false,"description":"The nextCursor from the previous page of this SAME query, to get the next page. Omit for the first page.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"How many to return, 1-100. Default 25.","schema":{"type":"number"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/api/public/freshness":{"get":{"operationId":"get_data_freshness","summary":"How current is this data","description":"When each home port was last pulled from Royal Caribbean, and how much fare history exists. Inventory is refreshed on a schedule, not per request, so fares can be a day or two old. Call this before presenting a fare as current, and tell the user the age if it matters to their decision.","parameters":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/api/public/back-to-backs/{id}":{"get":{"operationId":"get_back_to_back","summary":"One back-to-back by id","description":"Fetch a single back-to-back by the `id` carried on every search result, with both legs, every port of call, and the fare-history signal for each leg. Use this to follow up on a specific result the user asked about, or to re-check one before quoting it. Ids are built from the two sailing ids and stop resolving when either sailing leaves our inventory, or when the sailings turn out not to connect. A null result means the trip is not offered, so do not present it as bookable.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The back-to-back id from a search result: the two sailing ids joined with \"+\"."}],"responses":{"200":{"description":"The trip, or `result: null` with an explanation when the id no longer resolves."}}}}},"externalDocs":{"url":"https://legtolegcruises.com/for-ai","description":"What this data is, how it is built, and how to cite it."}}