{
  "openapi": "3.1.1",
  "info": {
    "title": "Focus Room Countdown API",
    "version": "1.0.0",
    "summary": "Time left until a moment in any time zone, with working days, holidays and a calendar file.",
    "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://focusroomcountdown.usefulweb.app"
    }
  ],
  "paths": {
    "/api/v1/calculate": {
      "post": {
        "operationId": "calculate",
        "summary": "Time left until a moment in any time zone, with working days, holidays and a calendar file.",
        "description": "Counts down to a date and time in any IANA time zone: days, hours, minutes and seconds left, calendar days and working days before the event day (weekends of your choice and public holidays of 16 countries skipped), daylight-saving changes on the way, the same moment on other clocks, and an .ics calendar event. The “New Year in every time zone” mode lists when midnight arrives from Kiritimati to Baker Island. The Focus Room app shows the same countdown full screen.\n\nMethodology:\n- Time zones come from the IANA time-zone database through the platform’s Intl implementation. The event’s wall-clock time is converted to an instant by trying the zone’s offsets around it: a time that does not exist (the hour skipped when clocks go forward) moves forward by the gap, a time that happens twice (clocks go back) takes the earlier one; both cases are reported.\n- Remaining time is the exact difference between the two instants, split into days of 24 hours, hours, minutes and seconds. Calendar days count from today’s date in the event zone to the event day.\n- Working days count the dates from today (inclusive) up to the event day (exclusive) that are neither a chosen weekend day nor a public holiday of the chosen country (nationwide, or of the given region). Holiday data: RuleDate’s Nager.Date set for 2024–2030.\n- New Year mode: for every time zone in the built-in list (each distinct UTC offset in use, from UTC+14 to UTC−12) the instant of local midnight on 1 January is computed and zones that share it are grouped.\n- The .ics file follows RFC 5545 with the start in UTC, so calendar apps show it at the correct local time anywhere; UID and DTSTAMP are derived from the event, so the same input gives the same file.\n\nTime-zone rules change from time to time; far-future countdowns follow today’s rules. Check holidays that matter (company closures, bridge days) yourself.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "focusroom_countdown",
        "x-owner-app": "focusroom",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FocusroomCountdownInput"
              },
              "examples": {
                "example1": {
                  "summary": "Product launch in Berlin, German holidays, seen from New York and Tokyo",
                  "value": {
                    "event": "custom",
                    "title": "Launch",
                    "target": "2027-03-15T09:00",
                    "zone": "Europe/Berlin",
                    "from": "2026-12-21T09:00",
                    "country": "DE",
                    "otherZones": [
                      "America/New_York",
                      "Asia/Tokyo"
                    ],
                    "alarmMinutes": 30
                  }
                },
                "example2": {
                  "summary": "New Year 2027 in every time zone, counted from Christmas Eve",
                  "value": {
                    "event": "new-year",
                    "title": "New Year",
                    "zone": "Europe/London",
                    "from": "2026-12-24T18:00"
                  }
                },
                "example3": {
                  "summary": "Exam in Riyadh with a Friday–Saturday weekend",
                  "value": {
                    "event": "custom",
                    "title": "Final exam",
                    "target": "2027-01-17T08:00",
                    "zone": "Asia/Riyadh",
                    "from": "2026-12-31T12:00",
                    "weekend": "fri-sat"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FocusroomCountdownResult"
                }
              }
            }
          },
          "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"
                }
              }
            }
          }
        }
      },
      "FocusroomCountdownInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "event": {
            "title": "Event",
            "type": "string",
            "enum": [
              "custom",
              "new-year"
            ],
            "default": "custom"
          },
          "title": {
            "title": "Title",
            "type": "string",
            "maxLength": 100,
            "default": "Launch"
          },
          "target": {
            "title": "Date and time of the event",
            "description": "Wall-clock time in the event’s time zone. Not used for New Year. Local date-time YYYY-MM-DDTHH:mm",
            "type": "string",
            "default": "2027-03-15T09:00"
          },
          "zone": {
            "title": "Time zone of the event",
            "description": "IANA time-zone name such as Europe/Berlin, America/New_York, Asia/Kolkata or UTC.",
            "type": "string",
            "maxLength": 64,
            "default": "Europe/Berlin"
          },
          "from": {
            "title": "Count from (optional)",
            "description": "Wall-clock time in the event’s time zone. Empty = now (rounded down to the minute). Local date-time YYYY-MM-DDTHH:mm",
            "type": "string"
          },
          "country": {
            "title": "Public holidays",
            "description": "Holidays on weekdays are not counted as working days (data 2024–2030).",
            "type": "string",
            "enum": [
              "none",
              "AT",
              "AU",
              "BE",
              "CA",
              "CH",
              "DE",
              "DK",
              "ES",
              "FR",
              "GB",
              "IE",
              "IT",
              "NL",
              "PL",
              "SE",
              "US"
            ],
            "default": "none"
          },
          "subdivision": {
            "title": "Region (optional)",
            "description": "ISO 3166-2 code such as DE-BY or US-CA for regional holidays.",
            "type": "string",
            "maxLength": 10,
            "default": ""
          },
          "weekend": {
            "title": "Weekend days",
            "type": "string",
            "enum": [
              "sat-sun",
              "fri-sat",
              "sun",
              "none"
            ],
            "default": "sat-sun"
          },
          "otherZones": {
            "title": "Show the moment in these time zones",
            "description": "One IANA name per line.",
            "type": "array",
            "items": {
              "type": "string"
            },
            "maxItems": 12,
            "default": []
          },
          "alarmMinutes": {
            "title": "Reminder in the calendar file",
            "description": "0 = no reminder.",
            "type": "integer",
            "minimum": 0,
            "maximum": 10080,
            "default": 0,
            "x-unit": "min"
          }
        },
        "required": []
      },
      "FocusroomCountdownResult": {
        "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": [
              "title",
              "target",
              "zone",
              "targetUtc",
              "from",
              "past",
              "remainingSeconds",
              "days",
              "hours",
              "minutes",
              "seconds",
              "totalHours",
              "calendarDays",
              "workingDays",
              "weekendDays",
              "weekend",
              "holidays",
              "holidayDataCovers",
              "offsetNow",
              "offsetAtTarget",
              "dstChange",
              "moments",
              "newYear",
              "icsFile"
            ],
            "properties": {
              "title": {
                "type": "string"
              },
              "target": {
                "type": "string",
                "description": "Local date-time YYYY-MM-DD HH:MM in the event zone."
              },
              "zone": {
                "type": "string"
              },
              "targetUtc": {
                "type": "string"
              },
              "from": {
                "type": "string"
              },
              "past": {
                "type": "boolean"
              },
              "remainingSeconds": {
                "type": "integer",
                "description": "Negative when the moment has passed."
              },
              "days": {
                "type": "integer"
              },
              "hours": {
                "type": "integer"
              },
              "minutes": {
                "type": "integer"
              },
              "seconds": {
                "type": "integer"
              },
              "totalHours": {
                "type": "number"
              },
              "calendarDays": {
                "type": "integer",
                "description": "Days from today (in the event zone) to the event day."
              },
              "workingDays": {
                "type": "integer",
                "description": "Working days from today (inclusive) to the event day (exclusive)."
              },
              "weekendDays": {
                "type": "integer"
              },
              "weekend": {
                "type": "string"
              },
              "holidays": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "date",
                    "name"
                  ],
                  "properties": {
                    "date": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    }
                  }
                }
              },
              "holidayDataCovers": {
                "type": "boolean"
              },
              "offsetNow": {
                "type": "string"
              },
              "offsetAtTarget": {
                "type": "string"
              },
              "dstChange": {
                "type": "boolean"
              },
              "moments": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "zone",
                    "city",
                    "local",
                    "weekday",
                    "offset"
                  ],
                  "properties": {
                    "zone": {
                      "type": "string"
                    },
                    "city": {
                      "type": "string"
                    },
                    "local": {
                      "type": "string"
                    },
                    "weekday": {
                      "type": "string"
                    },
                    "offset": {
                      "type": "string"
                    }
                  }
                }
              },
              "newYear": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "utc",
                    "offset",
                    "zones"
                  ],
                  "properties": {
                    "utc": {
                      "type": "string"
                    },
                    "offset": {
                      "type": "string"
                    },
                    "zones": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              },
              "icsFile": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "artifactId",
                  "filename",
                  "mime",
                  "bytes",
                  "sha256",
                  "path"
                ],
                "properties": {
                  "artifactId": {
                    "type": "string"
                  },
                  "filename": {
                    "type": "string"
                  },
                  "mime": {
                    "type": "string"
                  },
                  "bytes": {
                    "type": "integer"
                  },
                  "sha256": {
                    "type": "string"
                  },
                  "path": {
                    "type": "string",
                    "description": "Download path on the same site (valid for about 2 hours)."
                  }
                }
              }
            }
          },
          "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"
              }
            }
          }
        }
      }
    }
  }
}