{
  "openapi": "3.1.1",
  "info": {
    "title": "Travel Connection Checker API",
    "version": "1.0.0",
    "summary": "Estimate your odds of making a flight connection, step by step.",
    "description": "Every endpoint performs the same calculation as the human page and returns inputs, result, units, assumptions, sources, warnings and computedAt. MCP endpoint: /mcp."
  },
  "servers": [
    {
      "url": "https://travelconnectionchecker.usefulweb.site"
    }
  ],
  "paths": {
    "/api/v1/calculate": {
      "post": {
        "operationId": "calculate",
        "summary": "Estimate your odds of making a flight connection, step by step.",
        "description": "Enter your arrival and onward departure times and what you have to do in between (terminal change, passport control, security, baggage). The checker adds up transparent time ranges for each step, compares them with your connection time and estimates the chance of making it under a simple inbound-delay model. It is an estimate, never a guarantee.\n\nMethodology:\n- Available time = scheduled departure − scheduled arrival − gate-closure minutes.\n- Required time = deplaning + walking (+ terminal change) + optional immigration, security and baggage re-check, each an editorial [best, typical, worst] range by airport size; walking and terminal transfer are multiplied by 1.4 (slow) / 1.0 / 0.8 (fast).\n- Buffer = available − required, for each of best/typical/worst.\n- Inbound delay model: on time with probability p, otherwise delay ~ Exponential(mean delay). P(miss) = (1 − p)·e^(−buffer/mean) if buffer ≥ 0, else 100%. P(make) = 1 − P(miss). Early arrivals and onward-flight delays are ignored (both would help).\n- Overall chance: total processing time is treated as a triangular distribution between the best, typical and worst totals, and P(make) is averaged over it numerically (400 slices). The best/worst columns show the chance if processing is at its fastest/slowest.\n- Verdict from the overall chance: ≥ 95% comfortable, ≥ 85% ok, ≥ 70% tight, ≥ 50% risky, below that very risky.\n\nA planning estimate from simplified assumptions — not a guarantee. Airline, airport and border procedures and queues vary widely.",
        "tags": [
          "home-travel"
        ],
        "x-mcp-tool": "travel_connection_checker",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TravelConnectionCheckerInput"
              },
              "examples": {
                "example1": {
                  "summary": "Schengen → non-Schengen at a large hub, 70 min",
                  "value": {
                    "arrival": "2026-11-03T09:40",
                    "departure": "2026-11-03T10:50",
                    "terminalChange": true,
                    "immigration": true,
                    "securityRecheck": false,
                    "baggageRecheck": false,
                    "airportSize": "large",
                    "walkingSpeed": "average",
                    "gateClosesMinutes": 15,
                    "onTimeProbability": 75,
                    "meanDelayMinutes": 35,
                    "officialMct": 50
                  }
                },
                "example2": {
                  "summary": "US arrival with baggage recheck, 2 h 30",
                  "value": {
                    "arrival": "2026-12-18T14:05",
                    "departure": "2026-12-18T16:35",
                    "terminalChange": true,
                    "immigration": true,
                    "securityRecheck": true,
                    "baggageRecheck": true,
                    "airportSize": "mega",
                    "walkingSpeed": "slow",
                    "gateClosesMinutes": 15,
                    "onTimeProbability": 75,
                    "meanDelayMinutes": 35
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TravelConnectionCheckerResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tool": {
      "get": {
        "operationId": "getToolDefinition",
        "summary": "Inputs, output schema and examples for this tool",
        "responses": {
          "200": {
            "description": "Tool definition.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Problem": {
        "type": "object",
        "description": "RFC 9457 problem details. 422 responses include per-field `errors`.",
        "required": [
          "type",
          "title",
          "status",
          "detail"
        ],
        "properties": {
          "type": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer"
          },
          "detail": {
            "type": "string"
          },
          "code": {
            "type": "string"
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "field",
                "message"
              ],
              "properties": {
                "field": {
                  "type": "string"
                },
                "message": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "TravelConnectionCheckerInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "arrival": {
            "title": "Scheduled arrival (local)",
            "type": "string",
            "description": "Local date-time YYYY-MM-DDTHH:mm"
          },
          "departure": {
            "title": "Scheduled onward departure (local, same airport)",
            "type": "string",
            "description": "Local date-time YYYY-MM-DDTHH:mm"
          },
          "terminalChange": {
            "title": "Terminal change",
            "type": "boolean",
            "default": false
          },
          "immigration": {
            "title": "Passport / immigration check",
            "type": "boolean",
            "default": false
          },
          "securityRecheck": {
            "title": "Security screening again",
            "type": "boolean",
            "default": false
          },
          "baggageRecheck": {
            "title": "Collect and re-check baggage",
            "type": "boolean",
            "default": false
          },
          "airportSize": {
            "title": "Airport size",
            "type": "string",
            "enum": [
              "small",
              "medium",
              "large",
              "mega"
            ],
            "default": "large"
          },
          "walkingSpeed": {
            "title": "Walking speed",
            "type": "string",
            "enum": [
              "slow",
              "average",
              "fast"
            ],
            "default": "average"
          },
          "gateClosesMinutes": {
            "title": "Gate closes before departure",
            "description": "Check your boarding pass; often 10–20 minutes.",
            "type": "integer",
            "minimum": 0,
            "maximum": 60,
            "default": 15,
            "x-unit": "min"
          },
          "onTimeProbability": {
            "title": "Inbound flight on-time probability",
            "description": "Planning default; replace with the route’s on-time record if you know it.",
            "type": "number",
            "minimum": 0,
            "maximum": 100,
            "default": 75,
            "x-unit": "%"
          },
          "meanDelayMinutes": {
            "title": "Average delay when late",
            "type": "number",
            "minimum": 1,
            "maximum": 600,
            "default": 35,
            "x-unit": "min"
          },
          "officialMct": {
            "title": "Official minimum connection time (if known)",
            "description": "From the airline/airport for your connection type.",
            "type": "integer",
            "minimum": 0,
            "maximum": 600,
            "x-unit": "min"
          }
        },
        "required": [
          "arrival",
          "departure"
        ]
      },
      "TravelConnectionCheckerResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "connectionMinutes",
              "availableMinutes",
              "requiredMinutes",
              "bufferMinutes",
              "overallProbabilityPercent",
              "probabilityPercent",
              "verdict",
              "belowOfficialMct",
              "steps"
            ],
            "properties": {
              "connectionMinutes": {
                "type": "number",
                "description": "Scheduled departure − scheduled arrival."
              },
              "availableMinutes": {
                "type": "number",
                "description": "Connection minus gate-closure time."
              },
              "requiredMinutes": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "best",
                  "typical",
                  "worst"
                ],
                "properties": {
                  "best": {
                    "type": "number"
                  },
                  "typical": {
                    "type": "number"
                  },
                  "worst": {
                    "type": "number"
                  }
                }
              },
              "bufferMinutes": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "best",
                  "typical",
                  "worst"
                ],
                "properties": {
                  "best": {
                    "type": "number"
                  },
                  "typical": {
                    "type": "number"
                  },
                  "worst": {
                    "type": "number"
                  }
                }
              },
              "overallProbabilityPercent": {
                "type": "number",
                "minimum": 0,
                "maximum": 100,
                "description": "Chance averaged over a triangular distribution of total processing time."
              },
              "probabilityPercent": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "best",
                  "typical",
                  "worst"
                ],
                "description": "Model chance of reaching the gate before it closes, for best/typical/worst processing times.",
                "properties": {
                  "best": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 100
                  },
                  "typical": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 100
                  },
                  "worst": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 100
                  }
                }
              },
              "verdict": {
                "type": "string",
                "enum": [
                  "comfortable",
                  "ok",
                  "tight",
                  "risky",
                  "very-risky"
                ]
              },
              "belowOfficialMct": {
                "type": [
                  "boolean",
                  "null"
                ]
              },
              "steps": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "step",
                    "best",
                    "typical",
                    "worst"
                  ],
                  "properties": {
                    "step": {
                      "type": "string"
                    },
                    "best": {
                      "type": "number"
                    },
                    "typical": {
                      "type": "number"
                    },
                    "worst": {
                      "type": "number"
                    }
                  }
                }
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      }
    }
  }
}