{
  "openapi": "3.1.0",
  "info": {
    "title": "Cruisello Cruise Search API",
    "description": "Search and compare cruise sailings across all major cruise lines. Returns structured JSON with pricing, itinerary details, ship info, and direct booking links.",
    "version": "1.0.0",
    "contact": {
      "email": "contact@cruisello.com"
    }
  },
  "servers": [
    {
      "url": "https://cruisello.com"
    }
  ],
  "components": {
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "description": "Every 4xx and 5xx response uses this shape. `error.code` is a stable machine-readable string; `error.message` is for humans.",
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "status",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "not_found",
                  "invalid_request",
                  "unauthorized",
                  "request_failed"
                ]
              },
              "status": {
                "type": "integer",
                "example": 404
              },
              "message": {
                "type": "string"
              },
              "documentation": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "A parameter was missing or malformed",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "NotFound": {
        "description": "No such endpoint or resource",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    }
  },
  "paths": {
    "/api/feed/sailings.json": {
      "get": {
        "operationId": "searchCruises",
        "summary": "Search and filter cruise sailings",
        "description": "Returns a paginated feed of cruise sailings matching the given filters. Supports filtering by region, date range, duration, cabin type, price, cruise line, ship, departure port, and more.",
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 1,
              "minimum": 1
            },
            "description": "Page number"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "minimum": 1,
              "maximum": 100
            },
            "description": "Results per page (max 100)"
          },
          {
            "name": "regions",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated region codes: CARIBBEAN, W_MED, E_MED, N_EUROPE, ALASKA, ASIA, OCEANIA, S_AMERICA, MIDDLE_EAST, AFRICA, TRANSATLANTIC, BRITISH_ISLES, HAWAII, ANTARCTICA"
          },
          {
            "name": "startDate",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Earliest departure (ISO 8601)"
          },
          {
            "name": "endDate",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Latest departure (ISO 8601)"
          },
          {
            "name": "minNights",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1
            },
            "description": "Minimum duration in nights"
          },
          {
            "name": "maxNights",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1
            },
            "description": "Maximum duration in nights"
          },
          {
            "name": "cabinType",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "inside",
                "oceanview",
                "balcony",
                "suite",
                "deluxe"
              ]
            },
            "description": "Cabin category (prices returned are for this type). Default: inside"
          },
          {
            "name": "guests",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 2,
              "minimum": 1,
              "maximum": 4
            },
            "description": "Number of guests. Default: 2"
          },
          {
            "name": "currency",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "EUR",
              "enum": [
                "EUR",
                "USD"
              ]
            },
            "description": "Display currency. Default: EUR"
          },
          {
            "name": "minPrice",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Minimum price per person"
          },
          {
            "name": "maxPrice",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Maximum price per person"
          },
          {
            "name": "minPricePerNight",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Min price per night per person"
          },
          {
            "name": "maxPricePerNight",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Max price per night per person"
          },
          {
            "name": "ships",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Cruise line slug (e.g. 'royal-caribbean') or 'line:ship' (e.g. 'msc-cruises:msc-grandiosa'). Comma-separate multiple."
          },
          {
            "name": "departurePorts",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated port slugs for departure filter"
          },
          {
            "name": "stopoverPorts",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated port slugs — only cruises visiting these ports"
          },
          {
            "name": "returnType",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "any",
                "same_port",
                "different_port"
              ]
            },
            "description": "'same_port' for roundtrips, 'different_port' for one-way"
          },
          {
            "name": "sortBy",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "date",
              "enum": [
                "date",
                "price",
                "price_per_night",
                "duration",
                "quality"
              ]
            },
            "description": "Sort field. Default: date"
          },
          {
            "name": "sortOrder",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "asc",
              "enum": [
                "asc",
                "desc"
              ]
            },
            "description": "Sort direction. Default: asc"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated cruise feed",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "title": {
                      "type": "string"
                    },
                    "updated": {
                      "type": "string",
                      "format": "date"
                    },
                    "totalItems": {
                      "type": "integer"
                    },
                    "page": {
                      "type": "integer"
                    },
                    "pageSize": {
                      "type": "integer"
                    },
                    "totalPages": {
                      "type": "integer"
                    },
                    "items": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string"
                          },
                          "url": {
                            "type": "string",
                            "format": "uri"
                          },
                          "bookingUrl": {
                            "type": "string",
                            "format": "uri"
                          },
                          "provider": {
                            "type": "object",
                            "properties": {
                              "name": {
                                "type": "string"
                              },
                              "url": {
                                "type": "string",
                                "format": "uri"
                              },
                              "logoUrl": {
                                "type": "string",
                                "format": "uri",
                                "description": "Cruise line logo URL"
                              }
                            }
                          },
                          "ship": {
                            "type": "string"
                          },
                          "departureDate": {
                            "type": "string",
                            "format": "date"
                          },
                          "returnDate": {
                            "type": "string",
                            "format": "date",
                            "description": "Computed return date (departure + nights)"
                          },
                          "nights": {
                            "type": "integer"
                          },
                          "embarkationPort": {
                            "type": "object",
                            "properties": {
                              "name": {
                                "type": "string"
                              },
                              "countryCode": {
                                "type": "string"
                              },
                              "region": {
                                "type": "string"
                              }
                            }
                          },
                          "isRoundTrip": {
                            "type": "boolean"
                          },
                          "ports": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "name": {
                                  "type": "string"
                                },
                                "countryCode": {
                                  "type": "string"
                                },
                                "region": {
                                  "type": "string"
                                }
                              }
                            },
                            "description": "Stopover ports visited during the cruise"
                          },
                          "price": {
                            "type": "object",
                            "nullable": true,
                            "properties": {
                              "amount": {
                                "type": "number"
                              },
                              "perNight": {
                                "type": "number"
                              },
                              "currency": {
                                "type": "string"
                              },
                              "guests": {
                                "type": "integer"
                              },
                              "cabinType": {
                                "type": "string"
                              }
                            }
                          }
                        }
                      }
                    },
                    "links": {
                      "type": "object",
                      "properties": {
                        "self": {
                          "type": "string"
                        },
                        "next": {
                          "type": "string"
                        },
                        "prev": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    }
  }
}