{
  "openapi": "3.1.0",
  "info": {
    "title": "Geoapify Timezone API",
    "version": "1.0.1",
    "description": "Look up the timezone and exact UTC offset at coordinates, or list offset transitions.",
    "contact": {
      "name": "Geoapify",
      "url": "https://geoapify.com",
      "email": "info@geoapify.com"
    }
  },
  "servers": [
    {
      "url": "https://api.geoapify.com/v1",
      "description": "Default API endpoint."
    },
    {
      "url": "https://api-eu.geoapify.com/v1",
      "description": "EU-focused endpoint. Geoapify service processing uses EU infrastructure."
    }
  ],
  "tags": [
    {
      "name": "Timezone",
      "description": "Timezones by coordinates."
    }
  ],
  "paths": {
    "/timezone": {
      "get": {
        "tags": [
          "Timezone"
        ],
        "operationId": "getTimezone",
        "summary": "Get the timezone and UTC offset at an instant",
        "description": "The optional at parameter defaults to the current time. Each timezone includes local time and its next known transition; null means none is known within the bundled range. Supported instants are from 2025-01-01 through 2031-12-31 (UTC). More than one timezone can be returned at a disputed boundary.",
        "parameters": [
          {
            "name": "lat",
            "in": "query",
            "required": true,
            "description": "Latitude.",
            "schema": {
              "type": "number",
              "minimum": -90,
              "maximum": 90
            }
          },
          {
            "name": "lon",
            "in": "query",
            "required": true,
            "description": "Longitude.",
            "schema": {
              "type": "number",
              "minimum": -180,
              "maximum": 180
            }
          },
          {
            "name": "at",
            "in": "query",
            "required": false,
            "description": "RFC 3339 instant with an offset. Defaults to now.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Timezone information.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TimezoneResult"
                },
                "example": {
                  "lat": 40.758,
                  "lon": -73.9855,
                  "at": "2027-01-15T14:00:00.000Z",
                  "tzdb_version": "2026e",
                  "timezones": [
                    {
                      "name": "America/New_York",
                      "type": "standard",
                      "utc_offset": "-05:00",
                      "offset_seconds": -18000,
                      "abbreviation": "EST",
                      "local_time": "2027-01-15T09:00:00.000-05:00",
                      "next_transition": {
                        "at": "2027-03-14T07:00:00.000Z",
                        "before": {
                          "type": "standard",
                          "utc_offset": "-05:00",
                          "offset_seconds": -18000,
                          "abbreviation": "EST"
                        },
                        "after": {
                          "type": "daylightSaving",
                          "utc_offset": "-04:00",
                          "offset_seconds": -14400,
                          "abbreviation": "EDT"
                        },
                        "offset_change_seconds": 3600,
                        "kind": "daylight-start"
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid coordinate, date, or range.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                },
                "examples": {
                  "invalidCoordinate": {
                    "summary": "Latitude outside the allowed range",
                    "value": {
                      "statusCode": 400,
                      "error": "Bad Request",
                      "message": "\"lat\" must be less than or equal to 90"
                    }
                  },
                  "unsupportedInstant": {
                    "summary": "Instant outside the bundled transition range",
                    "value": {
                      "statusCode": 400,
                      "error": "Bad Request",
                      "message": "at is outside the supported transition range"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid Geoapify API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                },
                "example": {
                  "statusCode": 401,
                  "error": "Unauthorized",
                  "message": "Invalid apiKey"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit or quota exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                },
                "example": {
                  "statusCode": 429,
                  "error": "Too Many Requests",
                  "message": "Quota exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal gateway error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                },
                "example": {
                  "statusCode": 500,
                  "error": "Internal Server Error",
                  "message": "Request failed, please try again later"
                }
              }
            }
          }
        }
      }
    },
    "/timezone/transitions": {
      "get": {
        "tags": [
          "Timezone"
        ],
        "operationId": "getTimezoneTransitions",
        "summary": "List timezone transitions within an interval",
        "description": "The interval is [from, to), with a maximum span of 366 days, within 2025-01-01 through 2032-01-01 (UTC).",
        "parameters": [
          {
            "name": "lat",
            "in": "query",
            "required": true,
            "description": "Latitude.",
            "schema": {
              "type": "number",
              "minimum": -90,
              "maximum": 90
            }
          },
          {
            "name": "lon",
            "in": "query",
            "required": true,
            "description": "Longitude.",
            "schema": {
              "type": "number",
              "minimum": -180,
              "maximum": 180
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": true,
            "description": "Inclusive RFC 3339 start instant.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": true,
            "description": "Exclusive RFC 3339 end instant.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Timezone information.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TimezoneTransitionsResult"
                },
                "example": {
                  "lat": 40.758,
                  "lon": -73.9855,
                  "from": "2027-01-01T00:00:00.000Z",
                  "to": "2028-01-01T00:00:00.000Z",
                  "tzdb_version": "2026e",
                  "timezones": [
                    {
                      "name": "America/New_York",
                      "transitions": [
                        {
                          "at": "2027-03-14T07:00:00.000Z",
                          "before": {
                            "type": "standard",
                            "utc_offset": "-05:00",
                            "offset_seconds": -18000,
                            "abbreviation": "EST"
                          },
                          "after": {
                            "type": "daylightSaving",
                            "utc_offset": "-04:00",
                            "offset_seconds": -14400,
                            "abbreviation": "EDT"
                          },
                          "offset_change_seconds": 3600,
                          "kind": "daylight-start"
                        },
                        {
                          "at": "2027-11-07T06:00:00.000Z",
                          "before": {
                            "type": "daylightSaving",
                            "utc_offset": "-04:00",
                            "offset_seconds": -14400,
                            "abbreviation": "EDT"
                          },
                          "after": {
                            "type": "standard",
                            "utc_offset": "-05:00",
                            "offset_seconds": -18000,
                            "abbreviation": "EST"
                          },
                          "offset_change_seconds": -3600,
                          "kind": "daylight-end"
                        }
                      ]
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid coordinate, date, or range.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                },
                "examples": {
                  "invalidCoordinate": {
                    "summary": "Latitude outside the allowed range",
                    "value": {
                      "statusCode": 400,
                      "error": "Bad Request",
                      "message": "\"lat\" must be less than or equal to 90"
                    }
                  },
                  "invalidInterval": {
                    "summary": "Reversed or overly long interval",
                    "value": {
                      "statusCode": 400,
                      "error": "Bad Request",
                      "message": "from must precede to, with an interval of at most 366 days"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid Geoapify API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                },
                "example": {
                  "statusCode": 401,
                  "error": "Unauthorized",
                  "message": "Invalid apiKey"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit or quota exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                },
                "example": {
                  "statusCode": 429,
                  "error": "Too Many Requests",
                  "message": "Quota exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal gateway error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                },
                "example": {
                  "statusCode": 500,
                  "error": "Internal Server Error",
                  "message": "Request failed, please try again later"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "GatewayError": {
        "type": "object",
        "required": [
          "statusCode",
          "error",
          "message"
        ],
        "properties": {
          "statusCode": {
            "type": "integer",
            "description": "HTTP status code returned by the gateway."
          },
          "error": {
            "type": "string",
            "description": "Standard HTTP error name."
          },
          "message": {
            "type": "string",
            "description": "Human-readable explanation of the error."
          }
        }
      },
      "TimezoneState": {
        "type": "object",
        "required": [
          "type",
          "utc_offset",
          "offset_seconds",
          "abbreviation"
        ],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "standard",
              "daylightSaving",
              "other"
            ]
          },
          "utc_offset": {
            "type": "string"
          },
          "offset_seconds": {
            "type": "integer"
          },
          "abbreviation": {
            "type": "string"
          }
        }
      },
      "Timezone": {
        "allOf": [
          {
            "$ref": "#/components/schemas/TimezoneState"
          },
          {
            "type": "object",
            "required": [
              "name",
              "local_time",
              "next_transition"
            ],
            "properties": {
              "name": {
                "type": "string"
              },
              "local_time": {
                "type": "string",
                "format": "date-time"
              },
              "next_transition": {
                "description": "Next known transition after at, or null if none is known within the bundled range.",
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/Transition"
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            }
          }
        ]
      },
      "Transition": {
        "type": "object",
        "required": [
          "at",
          "before",
          "after",
          "offset_change_seconds",
          "kind"
        ],
        "properties": {
          "at": {
            "type": "string",
            "format": "date-time"
          },
          "before": {
            "$ref": "#/components/schemas/TimezoneState"
          },
          "after": {
            "$ref": "#/components/schemas/TimezoneState"
          },
          "offset_change_seconds": {
            "type": "integer"
          },
          "kind": {
            "type": "string",
            "enum": [
              "daylight-start",
              "daylight-end",
              "offset-change",
              "designation-change"
            ]
          }
        }
      },
      "TimezoneResult": {
        "type": "object",
        "required": [
          "lat",
          "lon",
          "at",
          "tzdb_version",
          "timezones"
        ],
        "properties": {
          "lat": {
            "type": "number"
          },
          "lon": {
            "type": "number"
          },
          "at": {
            "type": "string",
            "format": "date-time"
          },
          "tzdb_version": {
            "type": "string"
          },
          "timezones": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Timezone"
            }
          }
        }
      },
      "TimezoneTransitionsResult": {
        "type": "object",
        "required": [
          "lat",
          "lon",
          "from",
          "to",
          "tzdb_version",
          "timezones"
        ],
        "properties": {
          "lat": {
            "type": "number"
          },
          "lon": {
            "type": "number"
          },
          "from": {
            "type": "string",
            "format": "date-time"
          },
          "to": {
            "type": "string",
            "format": "date-time"
          },
          "tzdb_version": {
            "type": "string"
          },
          "timezones": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "name",
                "transitions"
              ],
              "properties": {
                "name": {
                  "type": "string"
                },
                "transitions": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Transition"
                  }
                }
              }
            }
          }
        }
      }
    },
    "securitySchemes": {
      "ApiKeyInQuery": {
        "type": "apiKey",
        "in": "query",
        "name": "apiKey",
        "description": "Geoapify API key query parameter. Recommended authentication method for public APIs. API keys in URLs can be logged; use x-api-key for server-to-server clients."
      },
      "ApiKeyInHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key",
        "description": "Geoapify API key header. Supported as an alternative authentication method for public APIs."
      }
    }
  },
  "security": [
    {
      "ApiKeyInQuery": []
    },
    {
      "ApiKeyInHeader": []
    }
  ]
}
