{
  "openapi": "3.1.0",
  "info": {
    "title": "TimeZoneMeet API",
    "version": "1.0.0",
    "summary": "Convert a UTC instant into any IANA time zone.",
    "description": "Public API that converts a UTC timestamp into one or more IANA time zones, returning the local wall-clock time, a zoned ISO-8601 string, the UTC offset, the day of the week, and a DST flag for each zone.\n\nTwo ways to use it: the no-code embed widget (https://timezonemeet.app/embed.js, keyless) or this raw JSON endpoint. Raw JSON is best used with a free API key (1,000 requests/day) — get one at https://timezonemeet.app/developers.html. Keyless calls are rate-limited and intended for the widget.\n\nWhen you display the data, keep the attribution from the response (`attribution`/`url`).",
    "termsOfService": "https://timezonemeet.app/terms.html",
    "contact": { "name": "TimeZoneMeet", "url": "https://timezonemeet.app/contact.html" },
    "license": { "name": "Free for any use with attribution", "url": "https://timezonemeet.app/api.html#terms" }
  },
  "servers": [{ "url": "https://timezonemeet.app", "description": "Production" }],
  "externalDocs": { "description": "API docs", "url": "https://timezonemeet.app/api.html" },
  "paths": {
    "/api/convert": {
      "get": {
        "operationId": "convert",
        "summary": "Convert a UTC instant to one or more IANA time zones.",
        "security": [{}, { "ApiKeyHeader": [] }, { "BearerAuth": [] }, { "ApiKeyQuery": [] }],
        "parameters": [
          {
            "name": "utc",
            "in": "query",
            "required": true,
            "description": "ISO-8601 UTC timestamp (e.g. 2026-05-20T14:00:00Z) or the literal string 'now'.",
            "schema": { "type": "string", "examples": ["now", "2026-05-20T14:00:00Z"] }
          },
          {
            "name": "tz",
            "in": "query",
            "required": true,
            "description": "IANA time-zone identifier, or a comma-separated list (max 10). e.g. Europe/Paris or Europe/Paris,Asia/Tokyo,UTC.",
            "schema": { "type": "string", "examples": ["Europe/Paris", "Europe/Paris,Asia/Tokyo,UTC"] }
          },
          {
            "name": "key",
            "in": "query",
            "required": false,
            "description": "API key (alternative to the X-API-Key / Authorization header). Avoid putting keys in URLs that get logged.",
            "schema": { "type": "string" }
          }
        ],
        "responses": {
          "200": {
            "description": "Conversion succeeded.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ConvertResponse" } } }
          },
          "400": {
            "description": "Invalid request (missing/unparseable utc, missing/unknown tz, or more than 10 zones).",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
          },
          "401": {
            "description": "Invalid or revoked API key.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
          },
          "429": {
            "description": "Rate limited — daily quota or burst limit exceeded.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyHeader": { "type": "apiKey", "in": "header", "name": "X-API-Key", "description": "Free API key from https://timezonemeet.app/developers.html" },
      "BearerAuth": { "type": "http", "scheme": "bearer", "description": "Pass the API key as a Bearer token." },
      "ApiKeyQuery": { "type": "apiKey", "in": "query", "name": "key" }
    },
    "schemas": {
      "ConvertResponse": {
        "type": "object",
        "required": ["utc", "results", "provider", "url", "attribution"],
        "properties": {
          "utc": { "type": "string", "description": "The requested instant, normalized to ISO-8601 with milliseconds.", "examples": ["2026-05-20T14:00:00.000Z"] },
          "results": { "type": "array", "items": { "$ref": "#/components/schemas/ZoneResult" } },
          "provider": { "type": "string", "examples": ["TimeZoneMeet"] },
          "url": { "type": "string", "format": "uri", "examples": ["https://timezonemeet.app"] },
          "attribution": { "type": "string", "description": "Ready-made attribution string to display.", "examples": ["Times by TimeZoneMeet — https://timezonemeet.app"] }
        }
      },
      "ZoneResult": {
        "type": "object",
        "required": ["timezone", "localTime", "iso", "offset", "offsetMinutes", "abbreviation", "dayOfWeek", "isDst"],
        "properties": {
          "timezone": { "type": "string", "examples": ["Europe/Paris"] },
          "localTime": { "type": "string", "description": "Wall-clock time, YYYY-MM-DD HH:MM (24h), truncated to the minute.", "examples": ["2026-05-20 16:00"] },
          "iso": { "type": "string", "description": "The same instant as a zoned ISO-8601 string.", "examples": ["2026-05-20T16:00:00+02:00"] },
          "offset": { "type": "string", "description": "UTC offset, ±HH:MM.", "examples": ["+02:00"] },
          "offsetMinutes": { "type": "integer", "examples": [120] },
          "abbreviation": { "type": "string", "examples": ["CEST"] },
          "dayOfWeek": { "type": "string", "examples": ["Wednesday"] },
          "isDst": { "type": "boolean" }
        }
      },
      "Error": {
        "type": "object",
        "required": ["error"],
        "properties": {
          "error": { "type": "string", "examples": ["invalid_api_key", "daily_quota_exceeded"] },
          "limit": { "type": "integer", "description": "Present on daily_quota_exceeded." },
          "retry_after": { "type": "integer", "description": "Seconds; present on rate_limited." }
        }
      }
    }
  }
}
