{
  "openapi": "3.1.0",
  "info": {
    "title": "Cruise Itinerary Data API",
    "version": "1.0.0",
    "summary": "Cruise reference data, weekly fares, itineraries on the calendar, port traffic and a change feed.",
    "description": "Reference data and weekly fare snapshots for cruise lines, ships, ports and sailings, refreshed every Monday. Fares are snapshots from an inventory feed, not live bookable prices. A null fare means the cabin is not offered or is sold out; the feed does not distinguish.\n\n**Authentication.** Send `Authorization: Bearer <key>` or `X-API-Key: <key>`. Without a key you are anonymous, which covers the open endpoints at a lower rate limit. A malformed, unknown or revoked key is a 401, never a silent downgrade.\n\n**Plans.** Each endpoint lists the lowest plan that can call it in `x-required-plan`. Rate limits are per minute and some plans have a monthly call quota; both are reported in response headers. See /pricing for the current numbers.\n\n**Envelope.** Single objects come back as `{\"data\": {...}, \"meta\": {...}}`, lists as `{\"data\": [...], \"meta\": {as_of, page, per_page, total, has_more}}`, errors as `{\"error\": {status, code, message}}`. Every key is always present; absent values are null. Dates are YYYY-MM-DD. Money is whole US dollars.\n\n**Ids.** Lines, ships, ports, destinations, regions and cruises use slugs. Sailings use their integer id.\n\n**Caching.** Anonymous responses from open endpoints are cacheable for an hour and carry an ETag. Everything keyed is `private, no-store`.\n\n**Counting.** A keyed request that returns 2xx counts toward the monthly quota; errors do not.",
    "termsOfService": "https://cruise-itinerary.com/terms",
    "contact": {
      "name": "Cruise Itinerary",
      "url": "https://cruise-itinerary.com"
    }
  },
  "servers": [
    {
      "url": "https://cruise-itinerary.com",
      "description": "Production"
    }
  ],
  "tags": [
    {
      "name": "Service"
    },
    {
      "name": "Reference data"
    },
    {
      "name": "Resolver"
    },
    {
      "name": "Sailings"
    },
    {
      "name": "Ships and ports"
    },
    {
      "name": "Changes"
    },
    {
      "name": "Price index"
    },
    {
      "name": "Bulk exports"
    }
  ],
  "security": [
    {},
    {
      "bearerAuth": []
    },
    {
      "apiKeyHeader": []
    }
  ],
  "paths": {
    "/v1": {
      "get": {
        "tags": [
          "Service"
        ],
        "summary": "Service root",
        "description": "Name, version and links. Useful as a connectivity check; it needs no key.",
        "operationId": "getRoot",
        "x-required-plan": "anon",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Root"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                },
                "example": {
                  "data": {
                    "name": "Cruise Itinerary Data API",
                    "version": "1",
                    "docs": "https://cruise-itinerary.com/docs",
                    "openapi": "https://cruise-itinerary.com/openapi.json",
                    "as_of": "2026-09-28"
                  },
                  "meta": {
                    "as_of": "2026-09-28"
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/E429"
          },
          "500": {
            "$ref": "#/components/responses/E500"
          }
        },
        "security": [
          {},
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ]
      }
    },
    "/v1/status": {
      "get": {
        "tags": [
          "Service"
        ],
        "summary": "Data status",
        "description": "How fresh the data is and how much of it there is. Inventory is reloaded once a week; `next_scheduled_load` says when.",
        "operationId": "getStatus",
        "x-required-plan": "anon",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Status"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                },
                "example": {
                  "data": {
                    "as_of": "2026-09-28",
                    "counts": {
                      "sailings": 61010,
                      "ships": 517,
                      "ports_with_calls": 2790,
                      "lines": 43
                    },
                    "next_scheduled_load": "2026-10-05T03:20:00-07:00"
                  },
                  "meta": {
                    "as_of": "2026-09-28"
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/E429"
          },
          "500": {
            "$ref": "#/components/responses/E500"
          }
        },
        "security": [
          {},
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ]
      }
    },
    "/v1/lines": {
      "get": {
        "tags": [
          "Reference data"
        ],
        "summary": "List cruise lines",
        "description": "Every cruise line, alphabetical, with how many ships and upcoming sailings each has.",
        "operationId": "listLines",
        "x-required-plan": "anon",
        "parameters": [
          {
            "$ref": "#/components/parameters/page"
          },
          {
            "$ref": "#/components/parameters/per_page"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Line"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ListMeta"
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "id": "amawaterways",
                      "name": "AmaWaterways",
                      "ship_count": 38,
                      "sailing_count": 3199
                    },
                    {
                      "id": "american-cruise-lines",
                      "name": "American Cruise Lines",
                      "ship_count": 23,
                      "sailing_count": 696
                    }
                  ],
                  "meta": {
                    "as_of": "2026-09-28",
                    "page": 1,
                    "per_page": 2,
                    "total": 45,
                    "has_more": true
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          },
          "500": {
            "$ref": "#/components/responses/E500"
          }
        },
        "security": [
          {},
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ]
      }
    },
    "/v1/lines/{id}": {
      "get": {
        "tags": [
          "Reference data"
        ],
        "summary": "Get a cruise line",
        "description": "One line by slug.",
        "operationId": "getLine",
        "x-required-plan": "anon",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Line slug.",
            "schema": {
              "type": "string"
            },
            "example": "holland-america-line"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Line"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                },
                "example": {
                  "data": {
                    "id": "holland-america-line",
                    "name": "Holland America Line",
                    "ship_count": 13,
                    "sailing_count": 1234
                  },
                  "meta": {
                    "as_of": "2026-09-28"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          },
          "500": {
            "$ref": "#/components/responses/E500"
          }
        },
        "security": [
          {},
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ]
      }
    },
    "/v1/ships": {
      "get": {
        "tags": [
          "Reference data"
        ],
        "summary": "List ships",
        "description": "Ships, alphabetical. `q` matches part of the name or an exact IMO number.",
        "operationId": "listShips",
        "x-required-plan": "anon",
        "parameters": [
          {
            "$ref": "#/components/parameters/page"
          },
          {
            "$ref": "#/components/parameters/per_page"
          },
          {
            "name": "line",
            "in": "query",
            "required": false,
            "description": "Only ships of this line (slug).",
            "schema": {
              "type": "string"
            },
            "example": "holland-america-line"
          },
          {
            "name": "q",
            "in": "query",
            "required": false,
            "description": "Name contains, or exact IMO.",
            "schema": {
              "type": "string"
            },
            "example": "eurodam"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Ship"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ListMeta"
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "id": "eurodam",
                      "name": "Eurodam",
                      "line": {
                        "id": "holland-america-line",
                        "name": "Holland America Line"
                      },
                      "imo": "9378448",
                      "mmsi": "245206000",
                      "passengers": 2104,
                      "crew": 929,
                      "gross_tonnage": 86273,
                      "decks": 11,
                      "length_ft": 936,
                      "width_ft": 106,
                      "maiden_voyage": "2008-07-05",
                      "launched": "2008-01-01",
                      "refurbished": null,
                      "adults_only": false
                    },
                    {
                      "id": "koningsdam",
                      "name": "Koningsdam",
                      "line": {
                        "id": "holland-america-line",
                        "name": "Holland America Line"
                      },
                      "imo": "9692557",
                      "mmsi": "244830547",
                      "passengers": 2650,
                      "crew": 1025,
                      "gross_tonnage": 99500,
                      "decks": 12,
                      "length_ft": 935,
                      "width_ft": 115,
                      "maiden_voyage": "2016-04-04",
                      "launched": null,
                      "refurbished": null,
                      "adults_only": false
                    }
                  ],
                  "meta": {
                    "as_of": "2026-09-28",
                    "page": 1,
                    "per_page": 2,
                    "total": 13,
                    "has_more": true
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          },
          "500": {
            "$ref": "#/components/responses/E500"
          }
        },
        "security": [
          {},
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ]
      }
    },
    "/v1/ships/{id}": {
      "get": {
        "tags": [
          "Reference data"
        ],
        "summary": "Get a ship",
        "description": "One ship by slug.",
        "operationId": "getShip",
        "x-required-plan": "anon",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Ship slug.",
            "schema": {
              "type": "string"
            },
            "example": "eurodam"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Ship"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                },
                "example": {
                  "data": {
                    "id": "eurodam",
                    "name": "Eurodam",
                    "line": {
                      "id": "holland-america-line",
                      "name": "Holland America Line"
                    },
                    "imo": "9378448",
                    "mmsi": "245206000",
                    "passengers": 2104,
                    "crew": 929,
                    "gross_tonnage": 86273,
                    "decks": 11,
                    "length_ft": 936,
                    "width_ft": 106,
                    "maiden_voyage": "2008-07-05",
                    "launched": "2008-01-01",
                    "refurbished": null,
                    "adults_only": false
                  },
                  "meta": {
                    "as_of": "2026-09-28"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          },
          "500": {
            "$ref": "#/components/responses/E500"
          }
        },
        "security": [
          {},
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ]
      }
    },
    "/v1/ports": {
      "get": {
        "tags": [
          "Reference data"
        ],
        "summary": "List ports",
        "description": "Ports and scenic stops. Use `has_calls=true` for ports a ship is scheduled to visit. For matching free text to a port, use `/v1/resolve`.",
        "operationId": "listPorts",
        "x-required-plan": "anon",
        "parameters": [
          {
            "$ref": "#/components/parameters/page"
          },
          {
            "$ref": "#/components/parameters/per_page"
          },
          {
            "name": "q",
            "in": "query",
            "required": false,
            "description": "Name or alias contains.",
            "schema": {
              "type": "string"
            },
            "example": "miami"
          },
          {
            "name": "destination",
            "in": "query",
            "required": false,
            "description": "Destination slug.",
            "schema": {
              "type": "string"
            },
            "example": "miami"
          },
          {
            "name": "region",
            "in": "query",
            "required": false,
            "description": "Region slug.",
            "schema": {
              "type": "string"
            },
            "example": "caribbean"
          },
          {
            "name": "has_calls",
            "in": "query",
            "required": false,
            "description": "true: only ports with scheduled calls; false: only those without.",
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ]
            }
          },
          {
            "name": "kind",
            "in": "query",
            "required": false,
            "description": "port or scenic.",
            "schema": {
              "type": "string",
              "enum": [
                "port",
                "scenic"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Port"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ListMeta"
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "id": "miami",
                      "name": "Miami",
                      "kind": "port",
                      "latitude": 25.7890972,
                      "longitude": -80.2040435,
                      "destination": {
                        "id": "miami",
                        "name": "Miami"
                      },
                      "region": {
                        "id": "united-states",
                        "name": "United States"
                      },
                      "aliases": [],
                      "upcoming_calls": 2424
                    }
                  ],
                  "meta": {
                    "as_of": "2026-09-28",
                    "page": 1,
                    "per_page": 2,
                    "total": 1,
                    "has_more": false
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          },
          "500": {
            "$ref": "#/components/responses/E500"
          }
        },
        "security": [
          {},
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ]
      }
    },
    "/v1/ports/{id}": {
      "get": {
        "tags": [
          "Reference data"
        ],
        "summary": "Get a port",
        "description": "One port by slug. The numeric id of a port that was merged into another also works and returns the surviving port, with `meta.resolved_from` set to the id you sent.",
        "operationId": "getPort",
        "x-required-plan": "anon",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Port slug, or the numeric id of a merged legacy port.",
            "schema": {
              "type": "string"
            },
            "example": "miami"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Port"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                },
                "example": {
                  "data": {
                    "id": "miami",
                    "name": "Miami",
                    "kind": "port",
                    "latitude": 25.7890972,
                    "longitude": -80.2040435,
                    "destination": {
                      "id": "miami",
                      "name": "Miami"
                    },
                    "region": {
                      "id": "united-states",
                      "name": "United States"
                    },
                    "aliases": [],
                    "upcoming_calls": 2424
                  },
                  "meta": {
                    "as_of": "2026-09-28"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          },
          "500": {
            "$ref": "#/components/responses/E500"
          }
        },
        "security": [
          {},
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ]
      }
    },
    "/v1/destinations": {
      "get": {
        "tags": [
          "Reference data"
        ],
        "summary": "List destinations",
        "description": "Destinations with their region and a representative coordinate.",
        "operationId": "listDestinations",
        "x-required-plan": "anon",
        "parameters": [
          {
            "$ref": "#/components/parameters/page"
          },
          {
            "$ref": "#/components/parameters/per_page"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Destination"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ListMeta"
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "id": "abu-dhabi",
                      "name": "Abu Dhabi",
                      "region": {
                        "id": "middle-east",
                        "name": "Middle East"
                      },
                      "latitude": 24.453884,
                      "longitude": 54.3773438
                    },
                    {
                      "id": "acapulco",
                      "name": "Acapulco",
                      "region": {
                        "id": "mexico-region",
                        "name": "Mexico region"
                      },
                      "latitude": 16.863611,
                      "longitude": -99.8825
                    }
                  ],
                  "meta": {
                    "as_of": "2026-09-28",
                    "page": 1,
                    "per_page": 2,
                    "total": 379,
                    "has_more": true
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          },
          "500": {
            "$ref": "#/components/responses/E500"
          }
        },
        "security": [
          {},
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ]
      }
    },
    "/v1/regions": {
      "get": {
        "tags": [
          "Reference data"
        ],
        "summary": "List regions",
        "description": "The 18 top-level regions.",
        "operationId": "listRegions",
        "x-required-plan": "anon",
        "parameters": [
          {
            "$ref": "#/components/parameters/page"
          },
          {
            "$ref": "#/components/parameters/per_page"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Region"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ListMeta"
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "id": "africa",
                      "name": "Africa"
                    },
                    {
                      "id": "alaska-region",
                      "name": "Alaska region"
                    }
                  ],
                  "meta": {
                    "as_of": "2026-09-28",
                    "page": 1,
                    "per_page": 2,
                    "total": 18,
                    "has_more": true
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          },
          "500": {
            "$ref": "#/components/responses/E500"
          }
        },
        "security": [
          {},
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ]
      }
    },
    "/v1/resolve": {
      "get": {
        "tags": [
          "Resolver"
        ],
        "summary": "Resolve a name",
        "description": "Match free text such as \"Port Canaveral, Florida\" or \"Royal Caribbean Symphony of the Seas\" to ports, ships and lines. Returns up to five candidates, best first. Confidence is 1.0 for an exact name, about 0.9 to 0.97 after normalising accents, punctuation, country suffixes and aliases, and 0.85 or less for approximate matches. For many names at once, use the POST form.",
        "operationId": "resolve",
        "x-required-plan": "anon",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "description": "The text to match, up to 200 characters.",
            "schema": {
              "type": "string"
            },
            "example": "Port Canaveral, Florida"
          },
          {
            "name": "type",
            "in": "query",
            "required": false,
            "description": "Restrict to one kind of entity.",
            "schema": {
              "type": "string",
              "enum": [
                "port",
                "ship",
                "line"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ResolveCandidate"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ListMeta"
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "type": "port",
                      "id": "port-canaveral",
                      "name": "Port Canaveral",
                      "confidence": 0.9,
                      "match": "normalized"
                    }
                  ],
                  "meta": {
                    "as_of": "2026-09-28",
                    "page": 1,
                    "per_page": 1,
                    "total": 1,
                    "has_more": false
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          },
          "500": {
            "$ref": "#/components/responses/E500"
          }
        },
        "security": [
          {},
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ]
      },
      "post": {
        "tags": [
          "Resolver"
        ],
        "summary": "Resolve names in bulk",
        "description": "Up to 100 items per request. The response holds one entry per item, in order, each with its own candidate list.",
        "operationId": "resolveBatch",
        "x-required-plan": "free",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "items": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 100,
                    "items": {
                      "type": "object",
                      "properties": {
                        "q": {
                          "type": "string",
                          "maxLength": 200
                        },
                        "type": {
                          "type": "string",
                          "enum": [
                            "port",
                            "ship",
                            "line"
                          ]
                        }
                      },
                      "required": [
                        "q"
                      ],
                      "additionalProperties": false
                    }
                  }
                },
                "required": [
                  "items"
                ],
                "additionalProperties": false
              },
              "example": {
                "items": [
                  {
                    "q": "Port Canaveral",
                    "type": "port"
                  },
                  {
                    "q": "Allure of the seas"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ResolveBatchResult"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ListMeta"
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "q": "Port Canaveral",
                      "type": "port",
                      "candidates": [
                        {
                          "type": "port",
                          "id": "port-canaveral",
                          "name": "Port Canaveral",
                          "confidence": 1,
                          "match": "exact"
                        }
                      ]
                    },
                    {
                      "q": "Allure of the seas",
                      "type": null,
                      "candidates": [
                        {
                          "type": "ship",
                          "id": "allure-of-the-seas",
                          "name": "Allure of the Seas",
                          "confidence": 1,
                          "match": "exact"
                        }
                      ]
                    }
                  ],
                  "meta": {
                    "as_of": "2026-09-28",
                    "page": 1,
                    "per_page": 2,
                    "total": 2,
                    "has_more": false
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          },
          "500": {
            "$ref": "#/components/responses/E500"
          }
        }
      }
    },
    "/v1/price-index/latest": {
      "get": {
        "tags": [
          "Price index"
        ],
        "summary": "Latest price index",
        "description": "The all-lines Cruise Price Index plus the eight largest lines, for cabin `any` and segment `all`, over the last 12 loads. Ordered all lines first, then by line name, oldest load first. The series starts on 2026-09-06 at 100.",
        "operationId": "getPriceIndexLatest",
        "x-required-plan": "anon",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/PriceIndexPoint"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ListMeta"
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "observed_on": "2026-09-06",
                      "previous_on": null,
                      "line": null,
                      "cabin": "any",
                      "segment": "all",
                      "matched": 54299,
                      "index_value": 100,
                      "mean_log_change": null,
                      "pct_cut": null,
                      "pct_raised": null,
                      "pct_unavailable": null,
                      "avg_per_diem": null
                    },
                    {
                      "observed_on": "2026-09-07",
                      "previous_on": "2026-09-06",
                      "line": null,
                      "cabin": "any",
                      "segment": "all",
                      "matched": 54299,
                      "index_value": 99.9036,
                      "mean_log_change": -0.000964,
                      "pct_cut": 0.62,
                      "pct_raised": 0.52,
                      "pct_unavailable": 0.18,
                      "avg_per_diem": 464.59
                    }
                  ],
                  "meta": {
                    "as_of": "2026-09-28",
                    "page": 1,
                    "per_page": 45,
                    "total": 45,
                    "has_more": false
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/E429"
          },
          "500": {
            "$ref": "#/components/responses/E500"
          }
        },
        "security": [
          {},
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ]
      }
    },
    "/v1/sailings": {
      "get": {
        "tags": [
          "Sailings"
        ],
        "summary": "Search sailings",
        "description": "Upcoming sailings with their latest fares. Fares are weekly snapshots from the inventory feed, not live bookable prices. `port` matches sailings that call at a port (itinerary days), `embark_port` the departure port. `from` and `to` bound the departure date.",
        "operationId": "listSailings",
        "x-required-plan": "developer",
        "parameters": [
          {
            "$ref": "#/components/parameters/page"
          },
          {
            "$ref": "#/components/parameters/per_page"
          },
          {
            "name": "ship",
            "in": "query",
            "required": false,
            "description": "Ship slug.",
            "schema": {
              "type": "string"
            },
            "example": "eurodam"
          },
          {
            "name": "line",
            "in": "query",
            "required": false,
            "description": "Line slug.",
            "schema": {
              "type": "string"
            },
            "example": "holland-america-line"
          },
          {
            "name": "port",
            "in": "query",
            "required": false,
            "description": "Port slug; sailings that call there.",
            "schema": {
              "type": "string"
            },
            "example": "ketchikan"
          },
          {
            "name": "embark_port",
            "in": "query",
            "required": false,
            "description": "Departure port slug.",
            "schema": {
              "type": "string"
            },
            "example": "seattle"
          },
          {
            "name": "region",
            "in": "query",
            "required": false,
            "description": "Region slug.",
            "schema": {
              "type": "string"
            },
            "example": "alaska-region"
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Earliest departure date.",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2026-10-01"
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Latest departure date.",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2026-12-31"
          },
          {
            "name": "min_nights",
            "in": "query",
            "required": false,
            "description": "Minimum length.",
            "schema": {
              "type": "integer"
            },
            "example": 7
          },
          {
            "name": "max_nights",
            "in": "query",
            "required": false,
            "description": "Maximum length.",
            "schema": {
              "type": "integer"
            },
            "example": 14
          },
          {
            "name": "cabin",
            "in": "query",
            "required": false,
            "description": "Restrict to sailings with a fare in this cabin; also the cabin `max_fare` and `sort=fare` use.",
            "schema": {
              "type": "string",
              "enum": [
                "inside",
                "outside",
                "balcony",
                "suite"
              ]
            }
          },
          {
            "name": "max_fare",
            "in": "query",
            "required": false,
            "description": "Highest fare in USD (in `cabin`, or in any cabin when `cabin` is absent).",
            "schema": {
              "type": "integer"
            },
            "example": 800
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "departure (default) or fare, lowest first.",
            "schema": {
              "type": "string",
              "enum": [
                "departure",
                "fare"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Sailing"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ListMeta"
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "id": 14026605,
                      "cruise": {
                        "id": "1-night-pacific-northwest-eurodam-da8a2f",
                        "title": "1 Night Pacific Northwest"
                      },
                      "ship": {
                        "id": "eurodam",
                        "name": "Eurodam"
                      },
                      "line": {
                        "id": "holland-america-line",
                        "name": "Holland America Line"
                      },
                      "departure_date": "2026-10-03",
                      "return_date": "2026-10-04",
                      "nights": 1,
                      "embark_port": {
                        "id": "seattle",
                        "name": "Seattle"
                      },
                      "disembark_port": {
                        "id": "vancouver",
                        "name": "Vancouver"
                      },
                      "fares": {
                        "inside": null,
                        "outside": 129,
                        "balcony": 129,
                        "suite": 239
                      },
                      "currency": "USD",
                      "fares_changed_on": "2026-09-14",
                      "observed_on": "2026-09-28"
                    },
                    {
                      "id": 14324436,
                      "cruise": {
                        "id": "21-night-panama-canal-eurodam-19a3f5",
                        "title": "21 Night Panama Canal"
                      },
                      "ship": {
                        "id": "eurodam",
                        "name": "Eurodam"
                      },
                      "line": {
                        "id": "holland-america-line",
                        "name": "Holland America Line"
                      },
                      "departure_date": "2026-10-03",
                      "return_date": "2026-10-24",
                      "nights": 21,
                      "embark_port": {
                        "id": "seattle",
                        "name": "Seattle"
                      },
                      "disembark_port": {
                        "id": "ft-lauderdale",
                        "name": "Ft. Lauderdale"
                      },
                      "fares": {
                        "inside": null,
                        "outside": null,
                        "balcony": null,
                        "suite": null
                      },
                      "currency": "USD",
                      "fares_changed_on": "2026-09-07",
                      "observed_on": "2026-09-28"
                    }
                  ],
                  "meta": {
                    "as_of": "2026-09-28",
                    "page": 1,
                    "per_page": 2,
                    "total": 113,
                    "has_more": true
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          },
          "500": {
            "$ref": "#/components/responses/E500"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ]
      }
    },
    "/v1/sailings/{id}": {
      "get": {
        "tags": [
          "Sailings"
        ],
        "summary": "Get a sailing",
        "description": "One sailing with its day-by-day itinerary. Embark and disembark days are exact; days in between are estimated and labelled so.",
        "operationId": "getSailing",
        "x-required-plan": "developer",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Sailing id.",
            "schema": {
              "type": "string"
            },
            "example": 14026605
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/SailingDetail"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                },
                "example": {
                  "data": {
                    "id": 14026605,
                    "cruise": {
                      "id": "1-night-pacific-northwest-eurodam-da8a2f",
                      "title": "1 Night Pacific Northwest"
                    },
                    "ship": {
                      "id": "eurodam",
                      "name": "Eurodam"
                    },
                    "line": {
                      "id": "holland-america-line",
                      "name": "Holland America Line"
                    },
                    "departure_date": "2026-10-03",
                    "return_date": "2026-10-04",
                    "nights": 1,
                    "embark_port": {
                      "id": "seattle",
                      "name": "Seattle"
                    },
                    "disembark_port": {
                      "id": "vancouver",
                      "name": "Vancouver"
                    },
                    "fares": {
                      "inside": null,
                      "outside": 129,
                      "balcony": 129,
                      "suite": 239
                    },
                    "currency": "USD",
                    "fares_changed_on": "2026-09-14",
                    "observed_on": "2026-09-28",
                    "itinerary": [
                      {
                        "day_offset": 0,
                        "date": "2026-10-03",
                        "port": {
                          "id": "seattle",
                          "name": "Seattle",
                          "latitude": 47.6062095,
                          "longitude": -122.3320708
                        },
                        "kind": "embark",
                        "day_confidence": "exact"
                      },
                      {
                        "day_offset": 1,
                        "date": "2026-10-04",
                        "port": {
                          "id": "vancouver",
                          "name": "Vancouver",
                          "latitude": 49.261226,
                          "longitude": -123.1139268
                        },
                        "kind": "disembark",
                        "day_confidence": "exact"
                      }
                    ]
                  },
                  "meta": {
                    "as_of": "2026-09-28"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          },
          "500": {
            "$ref": "#/components/responses/E500"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ]
      }
    },
    "/v1/sailings/{id}/prices": {
      "get": {
        "tags": [
          "Sailings"
        ],
        "summary": "Fare history of a sailing",
        "description": "Every weekly snapshot of the sailing's four fares, oldest first. History starts on 2026-09-06 and continues after the sailing departs.",
        "operationId": "getSailingPrices",
        "x-required-plan": "business",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Sailing id.",
            "schema": {
              "type": "string"
            },
            "example": 14026605
          },
          {
            "$ref": "#/components/parameters/page"
          },
          {
            "$ref": "#/components/parameters/per_page"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/PriceSnapshot"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ListMeta"
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "observed_on": "2026-09-06",
                      "fares": {
                        "inside": 129,
                        "outside": 129,
                        "balcony": 129,
                        "suite": 239
                      },
                      "currency": "USD"
                    },
                    {
                      "observed_on": "2026-09-07",
                      "fares": {
                        "inside": 129,
                        "outside": 129,
                        "balcony": 129,
                        "suite": 239
                      },
                      "currency": "USD"
                    },
                    {
                      "observed_on": "2026-09-14",
                      "fares": {
                        "inside": null,
                        "outside": 129,
                        "balcony": 129,
                        "suite": 239
                      },
                      "currency": "USD"
                    }
                  ],
                  "meta": {
                    "as_of": "2026-09-28",
                    "page": 1,
                    "per_page": 3,
                    "total": 5,
                    "has_more": true
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          },
          "500": {
            "$ref": "#/components/responses/E500"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ]
      }
    },
    "/v1/cruises/{id}": {
      "get": {
        "tags": [
          "Sailings"
        ],
        "summary": "Get a cruise",
        "description": "A cruise is the product (title, ship, ordered stops); a sailing is one departure of it. Cruise slugs are permanent.",
        "operationId": "getCruise",
        "x-required-plan": "developer",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Cruise slug.",
            "schema": {
              "type": "string"
            },
            "example": "1-night-pacific-northwest-eurodam-da8a2f"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Cruise"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                },
                "example": {
                  "data": {
                    "id": "1-night-pacific-northwest-eurodam-da8a2f",
                    "title": "1 Night Pacific Northwest",
                    "ship": {
                      "id": "eurodam",
                      "name": "Eurodam"
                    },
                    "line": {
                      "id": "holland-america-line",
                      "name": "Holland America Line"
                    },
                    "nights": 1,
                    "embark_port": {
                      "id": "seattle",
                      "name": "Seattle"
                    },
                    "disembark_port": {
                      "id": "vancouver",
                      "name": "Vancouver"
                    },
                    "stops": [
                      {
                        "seq": 1,
                        "port": {
                          "id": "seattle",
                          "name": "Seattle"
                        }
                      },
                      {
                        "seq": 2,
                        "port": {
                          "id": "vancouver",
                          "name": "Vancouver"
                        }
                      }
                    ],
                    "next_departure": "2026-10-03",
                    "sailing_count": 2
                  },
                  "meta": {
                    "as_of": "2026-09-28"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          },
          "500": {
            "$ref": "#/components/responses/E500"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ]
      }
    },
    "/v1/ships/{id}/schedule": {
      "get": {
        "tags": [
          "Ships and ports"
        ],
        "summary": "Ship schedule",
        "description": "Where a ship is on each day: one row per stop, with sea days. When sailings overlap, the shortest one that covers a day owns it. Window limit: 400 days; default 90 days from today.",
        "operationId": "getShipSchedule",
        "x-required-plan": "developer",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Ship slug.",
            "schema": {
              "type": "string"
            },
            "example": "eurodam"
          },
          {
            "$ref": "#/components/parameters/page"
          },
          {
            "$ref": "#/components/parameters/per_page"
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "First day (default today).",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2026-10-03"
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Last day.",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2026-10-31"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ShipDay"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ListMeta"
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "date": "2026-10-03",
                      "seq": 0,
                      "kind": "embark",
                      "port": {
                        "id": "seattle",
                        "name": "Seattle",
                        "latitude": 47.6062095,
                        "longitude": -122.3320708
                      },
                      "day_confidence": "exact",
                      "sailing_id": 14026605
                    },
                    {
                      "date": "2026-10-04",
                      "seq": 0,
                      "kind": "turnaround",
                      "port": {
                        "id": "vancouver",
                        "name": "Vancouver",
                        "latitude": 49.261226,
                        "longitude": -123.1139268
                      },
                      "day_confidence": "exact",
                      "sailing_id": 14317445
                    },
                    {
                      "date": "2026-10-05",
                      "seq": 0,
                      "kind": "sea",
                      "port": null,
                      "day_confidence": "estimated",
                      "sailing_id": 14317445
                    }
                  ],
                  "meta": {
                    "as_of": "2026-09-28",
                    "page": 1,
                    "per_page": 3,
                    "total": 29,
                    "has_more": true
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          },
          "500": {
            "$ref": "#/components/responses/E500"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ]
      }
    },
    "/v1/ports/{id}/calendar": {
      "get": {
        "tags": [
          "Ships and ports"
        ],
        "summary": "Port traffic calendar",
        "description": "Ships, lower berths and turnarounds per day. Only days with at least one ship appear; a missing day has none. Window limit: 730 days; default 90 days from today. Berths count lower-berth capacity; real headcount runs 10 to 20 percent higher.",
        "operationId": "getPortCalendar",
        "x-required-plan": "business",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Port slug (or merged legacy id).",
            "schema": {
              "type": "string"
            },
            "example": "miami"
          },
          {
            "$ref": "#/components/parameters/page"
          },
          {
            "$ref": "#/components/parameters/per_page"
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "First day (default today).",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2026-11-01"
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Last day.",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2026-11-30"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/PortDay"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ListMeta"
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "date": "2026-11-01",
                      "ships": 7,
                      "berths": 26885,
                      "ships_no_capacity": 0,
                      "embark_ships": 6,
                      "disembark_ships": 7,
                      "turnaround_ships": 6,
                      "estimated_ships": 0,
                      "busy_pct": 90
                    },
                    {
                      "date": "2026-11-02",
                      "ships": 3,
                      "berths": 12560,
                      "ships_no_capacity": 0,
                      "embark_ships": 3,
                      "disembark_ships": 3,
                      "turnaround_ships": 3,
                      "estimated_ships": 0,
                      "busy_pct": 39
                    },
                    {
                      "date": "2026-11-05",
                      "ships": 4,
                      "berths": 11456,
                      "ships_no_capacity": 0,
                      "embark_ships": 4,
                      "disembark_ships": 4,
                      "turnaround_ships": 4,
                      "estimated_ships": 0,
                      "busy_pct": 30
                    }
                  ],
                  "meta": {
                    "as_of": "2026-09-28",
                    "page": 1,
                    "per_page": 3,
                    "total": 27,
                    "has_more": true
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          },
          "500": {
            "$ref": "#/components/responses/E500"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ]
      }
    },
    "/v1/ports/{id}/days/{date}": {
      "get": {
        "tags": [
          "Ships and ports"
        ],
        "summary": "Port day detail",
        "description": "The counts for one day plus the ships behind them. A day with no ships returns zero counts and an empty `calls` list.",
        "operationId": "getPortDay",
        "x-required-plan": "business",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Port slug (or merged legacy id).",
            "schema": {
              "type": "string"
            },
            "example": "miami"
          },
          {
            "name": "date",
            "in": "path",
            "required": true,
            "description": "YYYY-MM-DD.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-14"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/PortDayDetail"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                },
                "example": {
                  "data": {
                    "date": "2026-11-14",
                    "ships": 7,
                    "berths": 23928,
                    "ships_no_capacity": 1,
                    "embark_ships": 7,
                    "disembark_ships": 7,
                    "turnaround_ships": 7,
                    "estimated_ships": 0,
                    "busy_pct": 85,
                    "calls": [
                      {
                        "ship": {
                          "id": "carnival-magic",
                          "name": "Carnival Magic",
                          "passengers": 3690
                        },
                        "line": {
                          "id": "carnival-cruise-line",
                          "name": "Carnival Cruise Line"
                        },
                        "kind": "turnaround",
                        "day_confidence": "exact",
                        "sailing_id": 14252373
                      },
                      {
                        "ship": {
                          "id": "carnival-sunrise",
                          "name": "Carnival Sunrise",
                          "passengers": 2984
                        },
                        "line": {
                          "id": "carnival-cruise-line",
                          "name": "Carnival Cruise Line"
                        },
                        "kind": "turnaround",
                        "day_confidence": "exact",
                        "sailing_id": 14252960
                      },
                      {
                        "ship": {
                          "id": "msc-world-america",
                          "name": "MSC World America",
                          "passengers": 5240
                        },
                        "line": {
                          "id": "msc-cruises",
                          "name": "MSC Cruises"
                        },
                        "kind": "turnaround",
                        "day_confidence": "exact",
                        "sailing_id": 14290891
                      },
                      {
                        "ship": {
                          "id": "norwegian-luna",
                          "name": "Norwegian Luna",
                          "passengers": null
                        },
                        "line": {
                          "id": "norwegian-cruise-line",
                          "name": "Norwegian Cruise Line"
                        },
                        "kind": "turnaround",
                        "day_confidence": "exact",
                        "sailing_id": 14221900
                      },
                      {
                        "ship": {
                          "id": "freedom-of-the-seas",
                          "name": "Freedom of the Seas",
                          "passengers": 3634
                        },
                        "line": {
                          "id": "royal-caribbean",
                          "name": "Royal Caribbean"
                        },
                        "kind": "turnaround",
                        "day_confidence": "exact",
                        "sailing_id": 14240653
                      },
                      {
                        "ship": {
                          "id": "icon-of-the-seas",
                          "name": "Icon of the Seas",
                          "passengers": 5610
                        },
                        "line": {
                          "id": "royal-caribbean",
                          "name": "Royal Caribbean"
                        },
                        "kind": "turnaround",
                        "day_confidence": "exact",
                        "sailing_id": 14089008
                      },
                      {
                        "ship": {
                          "id": "scarlet-lady",
                          "name": "Scarlet Lady",
                          "passengers": 2770
                        },
                        "line": {
                          "id": "virgin-voyages",
                          "name": "Virgin Voyages"
                        },
                        "kind": "turnaround",
                        "day_confidence": "exact",
                        "sailing_id": 14199956
                      }
                    ]
                  },
                  "meta": {
                    "as_of": "2026-09-28"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          },
          "500": {
            "$ref": "#/components/responses/E500"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ]
      }
    },
    "/v1/changes": {
      "get": {
        "tags": [
          "Changes"
        ],
        "summary": "Change feed",
        "description": "What changed between consecutive weekly loads: fare moves per cabin, cabins appearing or vanishing, sailings added or removed, itineraries swapped. Newest load first. `kind` takes a comma-separated list.",
        "operationId": "listChanges",
        "x-required-plan": "business",
        "parameters": [
          {
            "$ref": "#/components/parameters/page"
          },
          {
            "$ref": "#/components/parameters/per_page"
          },
          {
            "name": "since",
            "in": "query",
            "required": false,
            "description": "Earliest detected_on.",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2026-09-14"
          },
          {
            "name": "until",
            "in": "query",
            "required": false,
            "description": "Latest detected_on.",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2026-09-28"
          },
          {
            "name": "kind",
            "in": "query",
            "required": false,
            "description": "Comma-separated: price_drop, price_rise, cabin_unavailable, cabin_available, sailing_added, sailing_removed, itinerary_changed.",
            "schema": {
              "type": "string"
            },
            "example": "price_drop,sailing_added"
          },
          {
            "name": "ship",
            "in": "query",
            "required": false,
            "description": "Ship slug.",
            "schema": {
              "type": "string"
            },
            "example": "eurodam"
          },
          {
            "name": "line",
            "in": "query",
            "required": false,
            "description": "Line slug.",
            "schema": {
              "type": "string"
            },
            "example": "holland-america-line"
          },
          {
            "name": "port",
            "in": "query",
            "required": false,
            "description": "Port slug; sailings that call there.",
            "schema": {
              "type": "string"
            },
            "example": "miami"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ChangeEvent"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ListMeta"
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "id": 254254,
                      "detected_on": "2026-09-28",
                      "previous_on": "2026-09-21",
                      "kind": "price_drop",
                      "sailing_id": 14038925,
                      "cruise_id": "7-night-eastern-caribbean-holiday-amber-cove-and-bahamas-nieuw-amsterdam-ecb222",
                      "previous_cruise_id": null,
                      "ship": {
                        "id": "nieuw-amsterdam",
                        "name": "Nieuw Amsterdam"
                      },
                      "line": {
                        "id": "holland-america-line",
                        "name": "Holland America Line"
                      },
                      "departure_date": "2026-12-20",
                      "cabin": "inside",
                      "old_value": 749,
                      "new_value": 699,
                      "currency": "USD"
                    },
                    {
                      "id": 254255,
                      "detected_on": "2026-09-28",
                      "previous_on": "2026-09-21",
                      "kind": "price_drop",
                      "sailing_id": 14038929,
                      "cruise_id": "9-night-eastern-caribbean-st-maarten-antigua-and-bahamas-nieuw-amsterdam-44b3c2",
                      "previous_cruise_id": null,
                      "ship": {
                        "id": "nieuw-amsterdam",
                        "name": "Nieuw Amsterdam"
                      },
                      "line": {
                        "id": "holland-america-line",
                        "name": "Holland America Line"
                      },
                      "departure_date": "2026-12-11",
                      "cabin": "inside",
                      "old_value": 899,
                      "new_value": 849,
                      "currency": "USD"
                    }
                  ],
                  "meta": {
                    "as_of": "2026-09-28",
                    "page": 1,
                    "per_page": 2,
                    "total": 869,
                    "has_more": true
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          },
          "500": {
            "$ref": "#/components/responses/E500"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ]
      }
    },
    "/v1/price-index": {
      "get": {
        "tags": [
          "Price index"
        ],
        "summary": "Price index series",
        "description": "The full series for one line, cabin and segment, oldest first. `line` is a slug, or omitted (or `all`) for all lines. Rows exist only where at least 30 sailings matched.",
        "operationId": "getPriceIndex",
        "x-required-plan": "business",
        "parameters": [
          {
            "$ref": "#/components/parameters/page"
          },
          {
            "$ref": "#/components/parameters/per_page"
          },
          {
            "name": "line",
            "in": "query",
            "required": false,
            "description": "Line slug or all.",
            "schema": {
              "type": "string"
            },
            "example": "carnival-cruise-line"
          },
          {
            "name": "cabin",
            "in": "query",
            "required": false,
            "description": "Cabin class (default any).",
            "schema": {
              "type": "string",
              "enum": [
                "inside",
                "outside",
                "balcony",
                "suite",
                "any"
              ]
            }
          },
          {
            "name": "segment",
            "in": "query",
            "required": false,
            "description": "all (default), w000_090, w091_180, w181_365, w366_plus, or a sail quarter like q2027_1.",
            "schema": {
              "type": "string"
            },
            "example": "w000_090"
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Earliest observed_on.",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2026-09-06"
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Latest observed_on.",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2026-09-28"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/PriceIndexPoint"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ListMeta"
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "observed_on": "2026-09-06",
                      "previous_on": null,
                      "line": {
                        "id": "carnival-cruise-line",
                        "name": "Carnival Cruise Line"
                      },
                      "cabin": "balcony",
                      "segment": "w000_090",
                      "matched": 300,
                      "index_value": 100,
                      "mean_log_change": null,
                      "pct_cut": null,
                      "pct_raised": null,
                      "pct_unavailable": null,
                      "avg_per_diem": null
                    },
                    {
                      "observed_on": "2026-09-07",
                      "previous_on": "2026-09-06",
                      "line": {
                        "id": "carnival-cruise-line",
                        "name": "Carnival Cruise Line"
                      },
                      "cabin": "balcony",
                      "segment": "w000_090",
                      "matched": 300,
                      "index_value": 100.3153,
                      "mean_log_change": 0.003148,
                      "pct_cut": 3,
                      "pct_raised": 7,
                      "pct_unavailable": 2.28,
                      "avg_per_diem": 150.02
                    },
                    {
                      "observed_on": "2026-09-14",
                      "previous_on": "2026-09-07",
                      "line": {
                        "id": "carnival-cruise-line",
                        "name": "Carnival Cruise Line"
                      },
                      "cabin": "balcony",
                      "segment": "w000_090",
                      "matched": 255,
                      "index_value": 100.3892,
                      "mean_log_change": 0.000737,
                      "pct_cut": 51.76,
                      "pct_raised": 42.35,
                      "pct_unavailable": 13.56,
                      "avg_per_diem": 148.1
                    }
                  ],
                  "meta": {
                    "as_of": "2026-09-28",
                    "page": 1,
                    "per_page": 50,
                    "total": 5,
                    "has_more": false
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          },
          "500": {
            "$ref": "#/components/responses/E500"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ]
      }
    },
    "/v1/exports": {
      "get": {
        "tags": [
          "Bulk exports"
        ],
        "summary": "List weekly exports",
        "description": "The last eight weekly bulk files, as gzipped CSV, with row counts and SHA-256 checksums. Column names match the API and ids are slugs, so files join to the `identity-*` files. `access: anon` files download without a key.",
        "operationId": "listExports",
        "x-required-plan": "platform",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ExportWeek"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ListMeta"
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "date": "2026-09-28",
                      "files": [
                        {
                          "name": "identity-lines.csv.gz",
                          "bytes": 901,
                          "rows": 45,
                          "sha256": "88aff6f5f821b9a1aa20d69906c003c10a61971621965745846e9ca727974916",
                          "access": "anon",
                          "url": "https://cruise-itinerary.com/v1/exports/2026-09-28/identity-lines.csv.gz"
                        },
                        {
                          "name": "identity-ships.csv.gz",
                          "bytes": 20361,
                          "rows": 674,
                          "sha256": "057b373853a8b2aaee3e54dfdddd02f92e435d307aece09ba6f80aad06011ce6",
                          "access": "anon",
                          "url": "https://cruise-itinerary.com/v1/exports/2026-09-28/identity-ships.csv.gz"
                        }
                      ]
                    }
                  ],
                  "meta": {
                    "as_of": "2026-09-28",
                    "page": 1,
                    "per_page": 1,
                    "total": 1,
                    "has_more": false
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          },
          "500": {
            "$ref": "#/components/responses/E500"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ]
      }
    },
    "/v1/exports/{date}/{file}": {
      "get": {
        "tags": [
          "Bulk exports"
        ],
        "summary": "Download an export file",
        "description": "Streams one gzipped CSV. `date` may be `latest`. Files named `identity-*` (lines, ships, ports, destinations, regions) need no key; the rest need Platform.",
        "operationId": "downloadExport",
        "x-required-plan": "anon",
        "parameters": [
          {
            "name": "date",
            "in": "path",
            "required": true,
            "description": "Export date from the listing, or latest.",
            "schema": {
              "type": "string"
            },
            "example": "latest"
          },
          {
            "name": "file",
            "in": "path",
            "required": true,
            "description": "File name from the listing.",
            "schema": {
              "type": "string"
            },
            "example": "identity-lines.csv.gz"
          }
        ],
        "responses": {
          "200": {
            "description": "The file.",
            "content": {
              "application/gzip": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          },
          "500": {
            "$ref": "#/components/responses/E500"
          }
        },
        "security": [
          {},
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ]
      }
    }
  },
  "webhooks": {
    "changes.batch": {
      "post": {
        "summary": "Change events after a weekly load",
        "operationId": "webhookChangesBatch",
        "x-required-plan": "business",
        "description": "Business plans and above can subscribe an HTTPS URL from the dashboard, with optional kind, ship, line and port filters. After each weekly load we POST the matching change events, up to 1,000 per delivery (`page` of `pages`). Respond with any 2xx within 10 seconds. Otherwise we retry after 5 minutes, 30 minutes, 2, 6, 12 and 24 hours, and 24 hours again (8 attempts), then mark the delivery failed; an endpoint with 20 consecutive failed deliveries is disabled. URLs that resolve to private, loopback or link-local addresses are refused.\n\n`X-CI-Signature: t=<unix>,v1=<hex>` where `v1 = HMAC_SHA256(secret, \"<t>.<raw request body>\")`, hex encoded, using the endpoint secret shown in the dashboard. Reject requests whose timestamp is far from your clock. The dashboard's \"send test\" delivers a `ping` with an empty `events` list.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookBatch"
              },
              "example": {
                "id": 1,
                "type": "changes.batch",
                "detected_on": "2026-09-28",
                "previous_on": "2026-09-21",
                "page": 1,
                "pages": 1,
                "events": [
                  {
                    "id": 254254,
                    "detected_on": "2026-09-28",
                    "previous_on": "2026-09-21",
                    "kind": "price_drop",
                    "sailing_id": 14038925,
                    "cruise_id": "7-night-eastern-caribbean-holiday-amber-cove-and-bahamas-nieuw-amsterdam-ecb222",
                    "previous_cruise_id": null,
                    "ship": {
                      "id": "nieuw-amsterdam",
                      "name": "Nieuw Amsterdam"
                    },
                    "line": {
                      "id": "holland-america-line",
                      "name": "Holland America Line"
                    },
                    "departure_date": "2026-12-20",
                    "cabin": "inside",
                    "old_value": 749,
                    "new_value": 699,
                    "currency": "USD"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Delivered."
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Meta": {
        "type": "object",
        "properties": {
          "as_of": {
            "oneOf": [
              {
                "type": "string",
                "description": "Date of the latest inventory load the response reflects.",
                "format": "date"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "as_of"
        ],
        "additionalProperties": false
      },
      "ListMeta": {
        "type": "object",
        "properties": {
          "as_of": {
            "oneOf": [
              {
                "type": "string",
                "description": "Date of the latest inventory load the response reflects.",
                "format": "date"
              },
              {
                "type": "null"
              }
            ]
          },
          "page": {
            "type": "integer",
            "description": "Current page, from 1."
          },
          "per_page": {
            "type": "integer",
            "description": "Rows per page."
          },
          "total": {
            "type": "integer",
            "description": "Rows matching the query across all pages."
          },
          "has_more": {
            "type": "boolean",
            "description": "True when a later page exists."
          }
        },
        "required": [
          "as_of",
          "page",
          "per_page",
          "total",
          "has_more"
        ],
        "additionalProperties": false
      },
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "status",
              "code",
              "message"
            ],
            "properties": {
              "status": {
                "type": "integer"
              },
              "code": {
                "type": "string",
                "enum": [
                  "bad_request",
                  "invalid_key",
                  "account_suspended",
                  "plan_required",
                  "not_found",
                  "rate_limited",
                  "quota_exceeded",
                  "method_not_allowed",
                  "internal"
                ]
              },
              "message": {
                "type": "string",
                "description": "Human-readable explanation; safe to show to a developer, not a stable string to match on."
              },
              "required_plan": {
                "type": "string",
                "description": "Present on plan_required: the lowest plan that can call the endpoint.",
                "enum": [
                  "free",
                  "developer",
                  "business",
                  "platform"
                ]
              }
            }
          }
        }
      },
      "Ref": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Slug."
          },
          "name": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "name"
        ],
        "additionalProperties": false
      },
      "Fares": {
        "type": "object",
        "properties": {
          "inside": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "outside": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "balcony": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "suite": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "inside",
          "outside",
          "balcony",
          "suite"
        ],
        "additionalProperties": false,
        "description": "Lowest fare in whole US dollars per cabin class. null means the cabin is not offered or is sold out; the feed does not say which."
      },
      "Line": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Slug."
          },
          "name": {
            "type": "string"
          },
          "ship_count": {
            "type": "integer"
          },
          "sailing_count": {
            "type": "integer",
            "description": "Upcoming sailings."
          }
        },
        "required": [
          "id",
          "name",
          "ship_count",
          "sailing_count"
        ],
        "additionalProperties": false
      },
      "Ship": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Slug."
          },
          "name": {
            "type": "string"
          },
          "line": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Ref"
              },
              {
                "type": "null"
              }
            ]
          },
          "imo": {
            "oneOf": [
              {
                "type": "string",
                "description": "IMO number, 7 digits."
              },
              {
                "type": "null"
              }
            ]
          },
          "mmsi": {
            "oneOf": [
              {
                "type": "string",
                "description": "MMSI, 9 digits."
              },
              {
                "type": "null"
              }
            ]
          },
          "passengers": {
            "oneOf": [
              {
                "type": "integer",
                "description": "Lower-berth capacity. Real headcount runs 10 to 20 percent higher."
              },
              {
                "type": "null"
              }
            ]
          },
          "crew": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "gross_tonnage": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "decks": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "length_ft": {
            "oneOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          },
          "width_ft": {
            "oneOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          },
          "maiden_voyage": {
            "oneOf": [
              {
                "type": "string",
                "format": "date"
              },
              {
                "type": "null"
              }
            ]
          },
          "launched": {
            "oneOf": [
              {
                "type": "string",
                "format": "date"
              },
              {
                "type": "null"
              }
            ]
          },
          "refurbished": {
            "oneOf": [
              {
                "type": "string",
                "format": "date"
              },
              {
                "type": "null"
              }
            ]
          },
          "adults_only": {
            "oneOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "id",
          "name",
          "line",
          "imo",
          "mmsi",
          "passengers",
          "crew",
          "gross_tonnage",
          "decks",
          "length_ft",
          "width_ft",
          "maiden_voyage",
          "launched",
          "refurbished",
          "adults_only"
        ],
        "additionalProperties": false
      },
      "Port": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Slug."
          },
          "name": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "description": "scenic marks a stretch of cruising the feed lists as a stop, such as a glacier.",
            "enum": [
              "port",
              "scenic"
            ]
          },
          "latitude": {
            "oneOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          },
          "longitude": {
            "oneOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          },
          "destination": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Ref"
              },
              {
                "type": "null"
              }
            ]
          },
          "region": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Ref"
              },
              {
                "type": "null"
              }
            ]
          },
          "aliases": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "upcoming_calls": {
            "type": "integer",
            "description": "Future days on which a ship is scheduled at this port."
          }
        },
        "required": [
          "id",
          "name",
          "kind",
          "latitude",
          "longitude",
          "destination",
          "region",
          "aliases",
          "upcoming_calls"
        ],
        "additionalProperties": false
      },
      "PortPoint": {
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "latitude": {
                "oneOf": [
                  {
                    "type": "number"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "longitude": {
                "oneOf": [
                  {
                    "type": "number"
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            },
            "required": [
              "id",
              "name",
              "latitude",
              "longitude"
            ],
            "additionalProperties": false
          },
          {
            "type": "null"
          }
        ]
      },
      "Destination": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "region": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Ref"
              },
              {
                "type": "null"
              }
            ]
          },
          "latitude": {
            "oneOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          },
          "longitude": {
            "oneOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "id",
          "name",
          "region",
          "latitude",
          "longitude"
        ],
        "additionalProperties": false
      },
      "Region": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "name"
        ],
        "additionalProperties": false
      },
      "Sailing": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Sailing id (the feed id). Sailings are the only entities with integer ids."
          },
          "cruise": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "Cruise slug."
              },
              "title": {
                "type": "string"
              }
            },
            "required": [
              "id",
              "title"
            ],
            "additionalProperties": false
          },
          "ship": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Ref"
              },
              {
                "type": "null"
              }
            ]
          },
          "line": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Ref"
              },
              {
                "type": "null"
              }
            ]
          },
          "departure_date": {
            "type": "string",
            "format": "date"
          },
          "return_date": {
            "oneOf": [
              {
                "type": "string",
                "format": "date"
              },
              {
                "type": "null"
              }
            ]
          },
          "nights": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "embark_port": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Ref"
              },
              {
                "type": "null"
              }
            ]
          },
          "disembark_port": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Ref"
              },
              {
                "type": "null"
              }
            ]
          },
          "fares": {
            "$ref": "#/components/schemas/Fares"
          },
          "currency": {
            "type": "string",
            "enum": [
              "USD"
            ]
          },
          "fares_changed_on": {
            "oneOf": [
              {
                "type": "string",
                "description": "Last load on which any fare moved.",
                "format": "date"
              },
              {
                "type": "null"
              }
            ]
          },
          "observed_on": {
            "oneOf": [
              {
                "type": "string",
                "description": "Load that produced these fares.",
                "format": "date"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "id",
          "cruise",
          "ship",
          "line",
          "departure_date",
          "return_date",
          "nights",
          "embark_port",
          "disembark_port",
          "fares",
          "currency",
          "fares_changed_on",
          "observed_on"
        ],
        "additionalProperties": false
      },
      "ItineraryDay": {
        "type": "object",
        "properties": {
          "day_offset": {
            "type": "integer",
            "description": "0 is departure day."
          },
          "date": {
            "type": "string",
            "format": "date"
          },
          "port": {
            "$ref": "#/components/schemas/PortPoint"
          },
          "kind": {
            "type": "string",
            "enum": [
              "embark",
              "call",
              "scenic",
              "sea",
              "disembark"
            ]
          },
          "day_confidence": {
            "type": "string",
            "description": "Embark and disembark days are exact. Days in between are estimated from leg distances, because the feed lists stops without day numbers.",
            "enum": [
              "exact",
              "estimated"
            ]
          }
        },
        "required": [
          "day_offset",
          "date",
          "port",
          "kind",
          "day_confidence"
        ],
        "additionalProperties": false
      },
      "SailingDetail": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Sailing"
          },
          {
            "type": "object",
            "properties": {
              "itinerary": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/ItineraryDay"
                }
              }
            },
            "required": [
              "itinerary"
            ],
            "additionalProperties": false
          }
        ]
      },
      "PriceSnapshot": {
        "type": "object",
        "properties": {
          "observed_on": {
            "type": "string",
            "format": "date"
          },
          "fares": {
            "$ref": "#/components/schemas/Fares"
          },
          "currency": {
            "type": "string",
            "enum": [
              "USD"
            ]
          }
        },
        "required": [
          "observed_on",
          "fares",
          "currency"
        ],
        "additionalProperties": false
      },
      "Cruise": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Slug. Permanent across weekly loads."
          },
          "title": {
            "type": "string"
          },
          "ship": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Ref"
              },
              {
                "type": "null"
              }
            ]
          },
          "line": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Ref"
              },
              {
                "type": "null"
              }
            ]
          },
          "nights": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "embark_port": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Ref"
              },
              {
                "type": "null"
              }
            ]
          },
          "disembark_port": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Ref"
              },
              {
                "type": "null"
              }
            ]
          },
          "stops": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "seq": {
                  "type": "integer",
                  "description": "Position in the itinerary, from 1. Not a day number."
                },
                "port": {
                  "$ref": "#/components/schemas/Ref"
                }
              },
              "required": [
                "seq",
                "port"
              ],
              "additionalProperties": false
            }
          },
          "next_departure": {
            "oneOf": [
              {
                "type": "string",
                "format": "date"
              },
              {
                "type": "null"
              }
            ]
          },
          "sailing_count": {
            "type": "integer"
          }
        },
        "required": [
          "id",
          "title",
          "ship",
          "line",
          "nights",
          "embark_port",
          "disembark_port",
          "stops",
          "next_departure",
          "sailing_count"
        ],
        "additionalProperties": false
      },
      "ShipDay": {
        "type": "object",
        "properties": {
          "date": {
            "type": "string",
            "format": "date"
          },
          "seq": {
            "type": "integer",
            "description": "Order within the day."
          },
          "kind": {
            "type": "string",
            "enum": [
              "embark",
              "call",
              "scenic",
              "sea",
              "disembark",
              "turnaround"
            ]
          },
          "port": {
            "$ref": "#/components/schemas/PortPoint"
          },
          "day_confidence": {
            "type": "string",
            "enum": [
              "exact",
              "estimated"
            ]
          },
          "sailing_id": {
            "type": "integer",
            "description": "The sailing that owns this day."
          }
        },
        "required": [
          "date",
          "seq",
          "kind",
          "port",
          "day_confidence",
          "sailing_id"
        ],
        "additionalProperties": false
      },
      "PortDay": {
        "type": "object",
        "properties": {
          "date": {
            "type": "string",
            "format": "date"
          },
          "ships": {
            "type": "integer",
            "description": "Distinct ships in port."
          },
          "berths": {
            "type": "integer",
            "description": "Sum of known lower-berth capacity."
          },
          "ships_no_capacity": {
            "type": "integer",
            "description": "Ships counted whose capacity is unknown."
          },
          "embark_ships": {
            "type": "integer",
            "description": "Includes turnarounds."
          },
          "disembark_ships": {
            "type": "integer",
            "description": "Includes turnarounds."
          },
          "turnaround_ships": {
            "type": "integer",
            "description": "Ships that disembark one sailing and embark the next the same day."
          },
          "estimated_ships": {
            "type": "integer",
            "description": "Ships whose day here is estimated rather than exact."
          },
          "busy_pct": {
            "oneOf": [
              {
                "type": "integer",
                "description": "Percentile among this port's busy days within a year either side. 100 is the busiest."
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "date",
          "ships",
          "berths",
          "ships_no_capacity",
          "embark_ships",
          "disembark_ships",
          "turnaround_ships",
          "estimated_ships",
          "busy_pct"
        ],
        "additionalProperties": false
      },
      "PortDayDetail": {
        "allOf": [
          {
            "$ref": "#/components/schemas/PortDay"
          },
          {
            "type": "object",
            "properties": {
              "calls": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "ship": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "name": {
                          "type": "string"
                        },
                        "passengers": {
                          "oneOf": [
                            {
                              "type": "integer"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        }
                      },
                      "required": [
                        "id",
                        "name",
                        "passengers"
                      ],
                      "additionalProperties": false
                    },
                    "line": {
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/Ref"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "kind": {
                      "type": "string",
                      "enum": [
                        "embark",
                        "call",
                        "scenic",
                        "disembark",
                        "turnaround"
                      ]
                    },
                    "day_confidence": {
                      "type": "string",
                      "enum": [
                        "exact",
                        "estimated"
                      ]
                    },
                    "sailing_id": {
                      "type": "integer"
                    }
                  },
                  "required": [
                    "ship",
                    "line",
                    "kind",
                    "day_confidence",
                    "sailing_id"
                  ],
                  "additionalProperties": false
                }
              }
            },
            "required": [
              "calls"
            ],
            "additionalProperties": false,
            "description": "The ships behind the counts. Named calls, not ships, because ships is already the count."
          }
        ]
      },
      "ChangeEvent": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "detected_on": {
            "type": "string",
            "description": "Load that revealed the change.",
            "format": "date"
          },
          "previous_on": {
            "type": "string",
            "description": "Load it was compared against.",
            "format": "date"
          },
          "kind": {
            "type": "string",
            "enum": [
              "price_drop",
              "price_rise",
              "cabin_unavailable",
              "cabin_available",
              "sailing_added",
              "sailing_removed",
              "itinerary_changed"
            ]
          },
          "sailing_id": {
            "type": "integer"
          },
          "cruise_id": {
            "oneOf": [
              {
                "type": "string",
                "description": "Cruise slug."
              },
              {
                "type": "null"
              }
            ]
          },
          "previous_cruise_id": {
            "oneOf": [
              {
                "type": "string",
                "description": "For itinerary_changed: the cruise it replaced."
              },
              {
                "type": "null"
              }
            ]
          },
          "ship": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Ref"
              },
              {
                "type": "null"
              }
            ]
          },
          "line": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Ref"
              },
              {
                "type": "null"
              }
            ]
          },
          "departure_date": {
            "type": "string",
            "format": "date"
          },
          "cabin": {
            "oneOf": [
              {
                "type": "string",
                "enum": [
                  "inside",
                  "outside",
                  "balcony",
                  "suite"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "old_value": {
            "oneOf": [
              {
                "type": "integer",
                "description": "Fare before, USD."
              },
              {
                "type": "null"
              }
            ]
          },
          "new_value": {
            "oneOf": [
              {
                "type": "integer",
                "description": "Fare after, USD."
              },
              {
                "type": "null"
              }
            ]
          },
          "currency": {
            "type": "string",
            "enum": [
              "USD"
            ]
          }
        },
        "required": [
          "id",
          "detected_on",
          "previous_on",
          "kind",
          "sailing_id",
          "cruise_id",
          "previous_cruise_id",
          "ship",
          "line",
          "departure_date",
          "cabin",
          "old_value",
          "new_value",
          "currency"
        ],
        "additionalProperties": false
      },
      "PriceIndexPoint": {
        "type": "object",
        "properties": {
          "observed_on": {
            "type": "string",
            "format": "date"
          },
          "previous_on": {
            "oneOf": [
              {
                "type": "string",
                "format": "date"
              },
              {
                "type": "null"
              }
            ]
          },
          "line": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Ref"
              },
              {
                "type": "null"
              }
            ]
          },
          "cabin": {
            "type": "string",
            "enum": [
              "inside",
              "outside",
              "balcony",
              "suite",
              "any"
            ]
          },
          "segment": {
            "type": "string",
            "description": "all, a booking window (w000_090, w091_180, w181_365, w366_plus) or a sail quarter such as q2027_1."
          },
          "matched": {
            "type": "integer",
            "description": "Sailings priced in both loads."
          },
          "index_value": {
            "type": "number",
            "description": "Chained index, 100 on 2026-09-06."
          },
          "mean_log_change": {
            "oneOf": [
              {
                "type": "number",
                "description": "Mean of ln(new/old) over matched sailings, each winsorized to -0.5..0.5."
              },
              {
                "type": "null"
              }
            ]
          },
          "pct_cut": {
            "oneOf": [
              {
                "type": "number",
                "description": "Percent of matched sailings whose fare fell."
              },
              {
                "type": "null"
              }
            ]
          },
          "pct_raised": {
            "oneOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          },
          "pct_unavailable": {
            "oneOf": [
              {
                "type": "number",
                "description": "Percent priced before and unpriced now, still listed."
              },
              {
                "type": "null"
              }
            ]
          },
          "avg_per_diem": {
            "oneOf": [
              {
                "type": "number",
                "description": "Mean fare per night, USD, over the matched set."
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "observed_on",
          "previous_on",
          "line",
          "cabin",
          "segment",
          "matched",
          "index_value",
          "mean_log_change",
          "pct_cut",
          "pct_raised",
          "pct_unavailable",
          "avg_per_diem"
        ],
        "additionalProperties": false
      },
      "ResolveCandidate": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "port",
              "ship",
              "line"
            ]
          },
          "id": {
            "type": "string",
            "description": "Slug."
          },
          "name": {
            "type": "string"
          },
          "confidence": {
            "type": "number",
            "description": "0 to 1. 1.0 is an exact name match; below about 0.6 is a guess.",
            "minimum": 0,
            "maximum": 1
          },
          "match": {
            "type": "string",
            "enum": [
              "exact",
              "alias",
              "normalized",
              "fuzzy"
            ]
          }
        },
        "required": [
          "type",
          "id",
          "name",
          "confidence",
          "match"
        ],
        "additionalProperties": false
      },
      "ResolveBatchResult": {
        "type": "object",
        "properties": {
          "q": {
            "type": "string"
          },
          "type": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "candidates": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ResolveCandidate"
            }
          }
        },
        "required": [
          "q",
          "type",
          "candidates"
        ],
        "additionalProperties": false
      },
      "Status": {
        "type": "object",
        "properties": {
          "as_of": {
            "oneOf": [
              {
                "type": "string",
                "format": "date"
              },
              {
                "type": "null"
              }
            ]
          },
          "counts": {
            "type": "object",
            "properties": {
              "sailings": {
                "type": "integer"
              },
              "ships": {
                "type": "integer",
                "description": "Ships with upcoming sailings."
              },
              "ports_with_calls": {
                "type": "integer"
              },
              "lines": {
                "type": "integer",
                "description": "Lines with upcoming sailings."
              }
            },
            "required": [
              "sailings",
              "ships",
              "ports_with_calls",
              "lines"
            ],
            "additionalProperties": false
          },
          "next_scheduled_load": {
            "type": "string",
            "description": "When the next weekly load is due (ISO 8601 with offset).",
            "format": "date-time"
          }
        },
        "required": [
          "as_of",
          "counts",
          "next_scheduled_load"
        ],
        "additionalProperties": false
      },
      "Root": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "version": {
            "type": "string"
          },
          "docs": {
            "type": "string",
            "format": "uri"
          },
          "openapi": {
            "type": "string",
            "format": "uri"
          },
          "as_of": {
            "oneOf": [
              {
                "type": "string",
                "format": "date"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "name",
          "version",
          "docs",
          "openapi",
          "as_of"
        ],
        "additionalProperties": false
      },
      "ExportWeek": {
        "type": "object",
        "properties": {
          "date": {
            "type": "string",
            "format": "date"
          },
          "files": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string"
                },
                "bytes": {
                  "type": "integer"
                },
                "rows": {
                  "type": "integer"
                },
                "sha256": {
                  "type": "string"
                },
                "access": {
                  "type": "string",
                  "enum": [
                    "anon",
                    "platform"
                  ]
                },
                "url": {
                  "type": "string",
                  "format": "uri"
                }
              },
              "required": [
                "name",
                "bytes",
                "rows",
                "sha256",
                "access",
                "url"
              ],
              "additionalProperties": false
            }
          }
        },
        "required": [
          "date",
          "files"
        ],
        "additionalProperties": false
      },
      "WebhookBatch": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Delivery id; the same on every retry of this delivery."
          },
          "type": {
            "type": "string",
            "enum": [
              "changes.batch",
              "ping"
            ]
          },
          "detected_on": {
            "oneOf": [
              {
                "type": "string",
                "format": "date"
              },
              {
                "type": "null"
              }
            ]
          },
          "previous_on": {
            "oneOf": [
              {
                "type": "string",
                "format": "date"
              },
              {
                "type": "null"
              }
            ]
          },
          "page": {
            "type": "integer"
          },
          "pages": {
            "type": "integer",
            "description": "Deliveries for this load; each holds up to 1,000 events."
          },
          "events": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ChangeEvent"
            }
          }
        },
        "required": [
          "id",
          "type",
          "detected_on",
          "previous_on",
          "page",
          "pages",
          "events"
        ],
        "additionalProperties": false
      }
    },
    "responses": {
      "E400": {
        "description": "Bad request: an unknown or malformed parameter. The message names it.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "status": 400,
                "code": "bad_request",
                "message": "Parameter 'cabin' must be one of: inside, outside, balcony, suite."
              }
            }
          }
        }
      },
      "E401": {
        "description": "The key is malformed, unknown or revoked. A bad key is never treated as anonymous.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "status": 401,
                "code": "invalid_key",
                "message": "The API key is malformed, unknown or revoked."
              }
            }
          }
        }
      },
      "E403": {
        "description": "The plan does not include this endpoint (`plan_required`, with `required_plan`), or the account is suspended (`account_suspended`).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "status": 403,
                "code": "plan_required",
                "message": "This endpoint needs the Business plan or above; this key is on the Developer plan.",
                "required_plan": "business"
              }
            }
          }
        }
      },
      "E404": {
        "description": "No such entity or endpoint.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "status": 404,
                "code": "not_found",
                "message": "No such ship."
              }
            }
          }
        }
      },
      "E429": {
        "description": "Per-minute rate limit (`rate_limited`, with `Retry-After`) or monthly quota (`quota_exceeded`) reached.",
        "headers": {
          "Retry-After": {
            "description": "Seconds until the rate window resets.",
            "schema": {
              "type": "integer"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "status": 429,
                "code": "rate_limited",
                "message": "Rate limit of 60 requests per minute exceeded. Retry in 31 seconds."
              }
            }
          }
        }
      },
      "E500": {
        "description": "Internal error. Safe to retry.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "status": 500,
                "code": "internal",
                "message": "Internal error. Try again; if it persists, contact support."
              }
            }
          }
        }
      }
    },
    "parameters": {
      "page": {
        "name": "page",
        "in": "query",
        "description": "Page number, from 1. Pages deeper than 100,000 rows are refused.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "default": 1
        }
      },
      "per_page": {
        "name": "per_page",
        "in": "query",
        "description": "Rows per page, 1 to 200.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 200,
          "default": 50
        }
      }
    },
    "headers": {
      "X-RateLimit-Limit": {
        "description": "Requests allowed per one-minute window.",
        "schema": {
          "type": "integer"
        }
      },
      "X-RateLimit-Remaining": {
        "description": "Requests left in the current window.",
        "schema": {
          "type": "integer"
        }
      }
    },
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Key from the dashboard: ci_live_ followed by 32 letters and digits."
      },
      "apiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "The same key, as a header."
      }
    }
  }
}