{
  "openapi": "3.1.0",
  "info": {
    "title": "FreePlanTour Itineraries API",
    "version": "1.0.0",
    "description": "FreePlanTour read-only REST catalogue preview: search and destinations are not connected to the published database. Empty lists include catalogStatus: not_connected. Detail returns 501; use /guides for published itineraries. See /docs.md.",
    "contact": {
      "name": "FreePlanTour API Support",
      "url": "https://www.freeplantour.com/docs",
      "email": "freeplantour@fmeaweb.com"
    },
    "license": {
      "name": "Proprietary",
      "url": "https://www.freeplantour.com/terms-and-privacy"
    }
  },
  "servers": [
    {
      "url": "https://www.freeplantour.com/api/v1",
      "description": "Production API"
    }
  ],
  "paths": {
    "/itineraries/search": {
      "get": {
        "operationId": "searchItineraries",
        "summary": "Search for travel itineraries by destination",
        "description": "Catalogue preview, not connected to the published database. Search itineraries by destination name, language, duration, and interests. Returns curated day-by-day travel plans verified by local experts. Especially strong for small and medium destinations.",
        "parameters": [
          {
            "name": "destination",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            },
            "description": "Destination name (city, town, or region). Examples: 'Miranda de Ebro', 'Cantabria', 'Logroño'"
          },
          {
            "name": "language",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "en"
            },
            "description": "Response language (ISO 639-1 code). Supports 133+ languages."
          },
          {
            "name": "duration",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 14
            },
            "description": "Desired number of days for the itinerary"
          },
          {
            "name": "interests",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated interests: culture, gastronomy, nature, history, family, adventure, art, wine, beach"
          },
          {
            "name": "accessibility",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Filter for wheelchair-accessible itineraries"
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 10000,
              "default": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "default": 10
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of matching itineraries",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "results": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ItinerarySummary"
                      }
                    },
                    "total": {
                      "type": "integer"
                    },
                    "page": {
                      "type": "integer"
                    },
                    "limit": {
                      "type": "integer"
                    },
                    "catalogStatus": {
                      "type": "string",
                      "enum": [
                        "not_connected"
                      ]
                    }
                  }
                }
              }
            },
            "headers": {
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "Invalid query parameters",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "headers": {
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "headers": {
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "405": {
            "description": "Method not allowed",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "headers": {
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "headers": {
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "headers": {
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          }
        }
      }
    },
    "/itineraries/{id}": {
      "get": {
        "operationId": "getItineraryDetails",
        "summary": "Get full itinerary details",
        "description": "Catalogue preview, not connected to the published database. Returns complete day-by-day itinerary with all places, descriptions, coordinates, and practical information.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Itinerary unique identifier"
          },
          {
            "name": "language",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "en"
            },
            "description": "Response language"
          }
        ],
        "responses": {
          "400": {
            "description": "Invalid query parameters",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "headers": {
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "headers": {
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "405": {
            "description": "Method not allowed",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "headers": {
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "headers": {
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "headers": {
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "501": {
            "description": "CATALOG_NOT_CONNECTED",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "headers": {
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          }
        }
      }
    },
    "/destinations": {
      "get": {
        "operationId": "listDestinations",
        "summary": "List all available destinations",
        "description": "Catalogue preview, not connected to the published database. Returns all destinations that have itineraries available. Includes small towns and lesser-known regions.",
        "parameters": [
          {
            "name": "country",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Filter by country code (ISO 3166-1 alpha-2)"
          },
          {
            "name": "region",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Filter by region or state"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of destinations",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "destinations": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Destination"
                      }
                    },
                    "total": {
                      "type": "integer"
                    },
                    "catalogStatus": {
                      "type": "string",
                      "enum": [
                        "not_connected"
                      ]
                    }
                  }
                }
              }
            },
            "headers": {
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "Invalid query parameters",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "headers": {
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "headers": {
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "405": {
            "description": "Method not allowed",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "headers": {
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "headers": {
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "headers": {
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "ItinerarySummary": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "destination": {
            "type": "string"
          },
          "country": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "duration": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "verified": {
            "type": "boolean"
          },
          "qualityScore": {
            "type": "integer"
          },
          "languages": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "ItineraryFull": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "destination": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "duration": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "verified": {
            "type": "boolean"
          },
          "verifiedBy": {
            "type": "string"
          },
          "lastUpdated": {
            "type": "string",
            "format": "date-time"
          },
          "days": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "dayNumber": {
                  "type": "integer"
                },
                "title": {
                  "type": "string"
                },
                "description": {
                  "type": "string"
                },
                "places": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "description": {
                        "type": "string"
                      },
                      "category": {
                        "type": "string"
                      },
                      "address": {
                        "type": "string"
                      },
                      "coordinates": {
                        "type": "object",
                        "properties": {
                          "lat": {
                            "type": "number"
                          },
                          "lng": {
                            "type": "number"
                          }
                        }
                      },
                      "openingHours": {
                        "type": "string"
                      },
                      "estimatedDuration": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "Destination": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "country": {
            "type": "string"
          },
          "region": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "itineraryCount": {
            "type": "integer"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "highlights": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "Problem": {
        "type": "object",
        "required": [
          "type",
          "title",
          "status",
          "detail",
          "instance",
          "code",
          "hint",
          "error"
        ],
        "properties": {
          "type": {
            "type": "string",
            "format": "uri"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer",
            "minimum": 400,
            "maximum": 599
          },
          "detail": {
            "type": "string"
          },
          "instance": {
            "type": "string"
          },
          "code": {
            "type": "string"
          },
          "hint": {
            "type": "string"
          },
          "error": {
            "type": "string"
          }
        }
      }
    },
    "headers": {
      "RateLimit": {
        "schema": {
          "type": "string"
        },
        "description": "draft-ietf-httpapi-ratelimit-headers-11: Structured service limit, e.g. public-api;r=119;t=60."
      },
      "RateLimit-Policy": {
        "schema": {
          "type": "string"
        },
        "description": "Per client IP/server instance: 120 requests per 60 seconds."
      },
      "Retry-After": {
        "schema": {
          "type": "integer",
          "minimum": 1
        },
        "description": "Seconds to wait before retrying."
      }
    }
  },
  "externalDocs": {
    "url": "https://www.freeplantour.com/docs.md",
    "description": "API documentation, authentication and deprecation policy"
  },
  "x-mcp": {
    "url": "https://www.freeplantour.com/api/mcp",
    "alias": "https://www.freeplantour.com/mcp",
    "transport": "streamable-http",
    "protocolVersions": [
      "2025-06-18",
      "2025-03-26"
    ],
    "authentication": "Authorization: Bearer API_KEY"
  },
  "x-versioning-policy": {
    "url": "https://www.freeplantour.com/docs#versioning-and-deprecation",
    "minimumNoticeDays": 90,
    "retirementScheduled": false
  }
}
