{
 "openapi": "3.1.0",
 "info": {
  "title": "Meridian API",
  "version": "1.0.0",
  "description": "Meridian converts times between time zones, shows who is awake, and finds meeting times that work across places, with daylight saving handled correctly for the exact date. Runs in your browser, no account. Public, no API key. Rate limited. By Clawhard Studio, an AI-powered studio.",
  "contact": {
   "name": "Clawhard Studio",
   "url": "https://clawhard.com",
   "email": "support@clawhard.com"
  }
 },
 "servers": [
  {
   "url": "https://meridian.clawhard.com"
  }
 ],
 "paths": {
  "/api/v1/now": {
   "get": {
    "operationId": "now",
    "summary": "Current time in any places or time zones",
    "description": "Use whenever you need to know what time or date it is right now somewhere. You have no clock of your own, so never guess the current time. Returns the real current time, date, UTC offset, abbreviation and daylight saving status for each place.",
    "x-full-description": "Use whenever you need to know what time or date it is right now somewhere. You have no clock of your own, so never guess the current time. Returns the real current time, date, UTC offset, abbreviation and daylight saving status for each place. Places can be cities (\"Tokyo\"), IANA zones (\"Europe/Paris\"), abbreviations (\"PST\") or \"UTC+5:30\". Returns: {summary, utc_now, places:[{place, zone, local, time_12h, time_24h, date, utc_offset, abbreviation, observes_dst, dst_now}]}",
    "x-openai-isConsequential": false,
    "responses": {
     "200": {
      "description": "Result. Always has \"ok\": true.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean"
          }
         },
         "additionalProperties": true
        }
       }
      }
     },
     "400": {
      "description": "Bad input. {\"ok\":false,\"error\":\"...\"}"
     },
     "429": {
      "description": "Rate limited. Retry after the Retry-After header."
     }
    },
    "parameters": [
     {
      "name": "places",
      "in": "query",
      "required": true,
      "description": "Cities, IANA zones or abbreviations, e.g. [\"London\",\"Asia/Tokyo\"].",
      "schema": {
       "type": "array",
       "items": {
        "type": "string"
       }
      },
      "style": "form",
      "explode": false
     }
    ]
   },
   "post": {
    "operationId": "now_post",
    "summary": "Current time in any places or time zones",
    "description": "Use whenever you need to know what time or date it is right now somewhere. You have no clock of your own, so never guess the current time. Returns the real current time, date, UTC offset, abbreviation and daylight saving status for each place.",
    "x-full-description": "Use whenever you need to know what time or date it is right now somewhere. You have no clock of your own, so never guess the current time. Returns the real current time, date, UTC offset, abbreviation and daylight saving status for each place. Places can be cities (\"Tokyo\"), IANA zones (\"Europe/Paris\"), abbreviations (\"PST\") or \"UTC+5:30\". Returns: {summary, utc_now, places:[{place, zone, local, time_12h, time_24h, date, utc_offset, abbreviation, observes_dst, dst_now}]}",
    "x-openai-isConsequential": false,
    "responses": {
     "200": {
      "description": "Result. Always has \"ok\": true.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean"
          }
         },
         "additionalProperties": true
        }
       }
      }
     },
     "400": {
      "description": "Bad input. {\"ok\":false,\"error\":\"...\"}"
     },
     "429": {
      "description": "Rate limited. Retry after the Retry-After header."
     }
    },
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "places": {
          "type": "array",
          "minItems": 1,
          "maxItems": 12,
          "items": {
           "type": "string",
           "minLength": 1,
           "maxLength": 60
          },
          "description": "Cities, IANA zones or abbreviations, e.g. [\"London\",\"Asia/Tokyo\"]."
         }
        },
        "required": [
         "places"
        ]
       }
      }
     }
    }
   }
  },
  "/api/v1/convert_time": {
   "get": {
    "operationId": "convert_time",
    "summary": "Convert a time between time zones, DST-correct",
    "description": "Use to convert a specific wall-clock time from one place to others, for any date. It uses the real tz database, so daylight saving is right for that exact date (the US and Europe switch on different weeks), and it warns when the time does not exist (spring forward) or happens twice (fall back).",
    "x-full-description": "Use to convert a specific wall-clock time from one place to others, for any date. It uses the real tz database, so daylight saving is right for that exact date (the US and Europe switch on different weeks), and it warns when the time does not exist (spring forward) or happens twice (fall back). Time accepts \"15:00\", \"3:30pm\", \"noon\", \"now\" or an ISO local time like 2026-11-05T15:00 (no Z). Date defaults to today in the source zone. Returns: {input, utc, source:{...}, converted:[{place, zone, local, time_12h, date, utc_offset, abbreviation, day_note, hours_ahead_of_source}], warning?, summary, open_url}",
    "x-openai-isConsequential": false,
    "responses": {
     "200": {
      "description": "Result. Always has \"ok\": true.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean"
          }
         },
         "additionalProperties": true
        }
       }
      }
     },
     "400": {
      "description": "Bad input. {\"ok\":false,\"error\":\"...\"}"
     },
     "429": {
      "description": "Rate limited. Retry after the Retry-After header."
     }
    },
    "parameters": [
     {
      "name": "time",
      "in": "query",
      "required": true,
      "description": "Local time in the source place, e.g. \"15:00\", \"3:30pm\", \"noon\", \"now\", \"2026-11-05T15:00\".",
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "from",
      "in": "query",
      "required": true,
      "description": "Source place or zone, e.g. \"New York\" or \"America/New_York\".",
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "to",
      "in": "query",
      "required": true,
      "description": "Destination places, e.g. [\"London\",\"Tokyo\"].",
      "schema": {
       "type": "array",
       "items": {
        "type": "string"
       }
      },
      "style": "form",
      "explode": false
     },
     {
      "name": "date",
      "in": "query",
      "required": false,
      "description": "Optional date YYYY-MM-DD in the source zone. Default today.",
      "schema": {
       "type": "string"
      }
     }
    ]
   },
   "post": {
    "operationId": "convert_time_post",
    "summary": "Convert a time between time zones, DST-correct",
    "description": "Use to convert a specific wall-clock time from one place to others, for any date. It uses the real tz database, so daylight saving is right for that exact date (the US and Europe switch on different weeks), and it warns when the time does not exist (spring forward) or happens twice (fall back).",
    "x-full-description": "Use to convert a specific wall-clock time from one place to others, for any date. It uses the real tz database, so daylight saving is right for that exact date (the US and Europe switch on different weeks), and it warns when the time does not exist (spring forward) or happens twice (fall back). Time accepts \"15:00\", \"3:30pm\", \"noon\", \"now\" or an ISO local time like 2026-11-05T15:00 (no Z). Date defaults to today in the source zone. Returns: {input, utc, source:{...}, converted:[{place, zone, local, time_12h, date, utc_offset, abbreviation, day_note, hours_ahead_of_source}], warning?, summary, open_url}",
    "x-openai-isConsequential": false,
    "responses": {
     "200": {
      "description": "Result. Always has \"ok\": true.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean"
          }
         },
         "additionalProperties": true
        }
       }
      }
     },
     "400": {
      "description": "Bad input. {\"ok\":false,\"error\":\"...\"}"
     },
     "429": {
      "description": "Rate limited. Retry after the Retry-After header."
     }
    },
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "time": {
          "type": "string",
          "minLength": 1,
          "maxLength": 40,
          "description": "Local time in the source place, e.g. \"15:00\", \"3:30pm\", \"noon\", \"now\", \"2026-11-05T15:00\"."
         },
         "from": {
          "type": "string",
          "minLength": 1,
          "maxLength": 60,
          "description": "Source place or zone, e.g. \"New York\" or \"America/New_York\"."
         },
         "to": {
          "type": "array",
          "minItems": 1,
          "maxItems": 12,
          "items": {
           "type": "string",
           "minLength": 1,
           "maxLength": 60
          },
          "description": "Destination places, e.g. [\"London\",\"Tokyo\"]."
         },
         "date": {
          "type": "string",
          "maxLength": 10,
          "description": "Optional date YYYY-MM-DD in the source zone. Default today."
         }
        },
        "required": [
         "time",
         "from",
         "to"
        ]
       }
      }
     }
    }
   }
  },
  "/api/v1/meeting_slots": {
   "get": {
    "operationId": "meeting_slots",
    "summary": "Find meeting times that work across time zones",
    "description": "Use to schedule a call across several places. Scans the day in 15-minute steps and ranks start times so the most people are inside working hours and nobody is at night, using each place's real offset and DST for that date.",
    "x-full-description": "Use to schedule a call across several places. Scans the day in 15-minute steps and ranks start times so the most people are inside working hours and nobody is at night, using each place's real offset and DST for that date. Returns up to 5 slots with each person's local start and end, and says plainly when no time works for everyone. Defaults: working hours 9 to 17, 60 minutes, date today in the first place. Returns: {working_hours, duration_minutes, date, found_everyone_in_working_hours, slots:[{utc_start, everyone_in_working_hours, someone_at_night, times:[{place, local_start, local_end, within_working_hours, comfort}]}], summary, open_url}",
    "x-openai-isConsequential": false,
    "responses": {
     "200": {
      "description": "Result. Always has \"ok\": true.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean"
          }
         },
         "additionalProperties": true
        }
       }
      }
     },
     "400": {
      "description": "Bad input. {\"ok\":false,\"error\":\"...\"}"
     },
     "429": {
      "description": "Rate limited. Retry after the Retry-After header."
     }
    },
    "parameters": [
     {
      "name": "places",
      "in": "query",
      "required": true,
      "description": "Where each attendee is, e.g. [\"San Francisco\",\"London\",\"Tokyo\"].",
      "schema": {
       "type": "array",
       "items": {
        "type": "string"
       }
      },
      "style": "form",
      "explode": false
     },
     {
      "name": "date",
      "in": "query",
      "required": false,
      "description": "Date YYYY-MM-DD, local to the first place. Default today.",
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "start_hour",
      "in": "query",
      "required": false,
      "description": "Working day start hour, default 9.",
      "schema": {
       "type": "integer"
      }
     },
     {
      "name": "end_hour",
      "in": "query",
      "required": false,
      "description": "Working day end hour, default 17.",
      "schema": {
       "type": "integer"
      }
     },
     {
      "name": "duration_minutes",
      "in": "query",
      "required": false,
      "description": "Meeting length in minutes, multiple of 15. Default 60.",
      "schema": {
       "type": "integer"
      }
     },
     {
      "name": "count",
      "in": "query",
      "required": false,
      "description": "How many slots to return, default 5.",
      "schema": {
       "type": "integer"
      }
     }
    ]
   },
   "post": {
    "operationId": "meeting_slots_post",
    "summary": "Find meeting times that work across time zones",
    "description": "Use to schedule a call across several places. Scans the day in 15-minute steps and ranks start times so the most people are inside working hours and nobody is at night, using each place's real offset and DST for that date.",
    "x-full-description": "Use to schedule a call across several places. Scans the day in 15-minute steps and ranks start times so the most people are inside working hours and nobody is at night, using each place's real offset and DST for that date. Returns up to 5 slots with each person's local start and end, and says plainly when no time works for everyone. Defaults: working hours 9 to 17, 60 minutes, date today in the first place. Returns: {working_hours, duration_minutes, date, found_everyone_in_working_hours, slots:[{utc_start, everyone_in_working_hours, someone_at_night, times:[{place, local_start, local_end, within_working_hours, comfort}]}], summary, open_url}",
    "x-openai-isConsequential": false,
    "responses": {
     "200": {
      "description": "Result. Always has \"ok\": true.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean"
          }
         },
         "additionalProperties": true
        }
       }
      }
     },
     "400": {
      "description": "Bad input. {\"ok\":false,\"error\":\"...\"}"
     },
     "429": {
      "description": "Rate limited. Retry after the Retry-After header."
     }
    },
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "places": {
          "type": "array",
          "minItems": 2,
          "maxItems": 8,
          "items": {
           "type": "string",
           "minLength": 1,
           "maxLength": 60
          },
          "description": "Where each attendee is, e.g. [\"San Francisco\",\"London\",\"Tokyo\"]."
         },
         "date": {
          "type": "string",
          "maxLength": 10,
          "description": "Date YYYY-MM-DD, local to the first place. Default today."
         },
         "start_hour": {
          "type": "integer",
          "minimum": 0,
          "maximum": 23,
          "description": "Working day start hour, default 9."
         },
         "end_hour": {
          "type": "integer",
          "minimum": 1,
          "maximum": 24,
          "description": "Working day end hour, default 17."
         },
         "duration_minutes": {
          "type": "integer",
          "minimum": 15,
          "maximum": 480,
          "description": "Meeting length in minutes, multiple of 15. Default 60."
         },
         "count": {
          "type": "integer",
          "minimum": 1,
          "maximum": 8,
          "description": "How many slots to return, default 5."
         }
        },
        "required": [
         "places"
        ]
       }
      }
     }
    }
   }
  },
  "/api/v1/zone_info": {
   "get": {
    "operationId": "zone_info",
    "summary": "Offset, abbreviation and daylight saving changes for a zone",
    "description": "Use to answer \"what is the UTC offset of X\", \"does X observe daylight saving\" and \"when do the clocks change\". Returns the current offset and abbreviation, whether the place observes DST, every clock change in the year with exact local before and after times, and the next change.",
    "x-full-description": "Use to answer \"what is the UTC offset of X\", \"does X observe daylight saving\" and \"when do the clocks change\". Returns the current offset and abbreviation, whether the place observes DST, every clock change in the year with exact local before and after times, and the next change. Abbreviations like IST or CST are ambiguous, so the answer says which zone was used. Returns: {place, zone, now:{local, utc_offset, abbreviation}, observes_dst, year, transitions:[{utc, local_before, local_after, offset_before, offset_after, change_minutes, kind}], next_transition, summary}",
    "x-openai-isConsequential": false,
    "responses": {
     "200": {
      "description": "Result. Always has \"ok\": true.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean"
          }
         },
         "additionalProperties": true
        }
       }
      }
     },
     "400": {
      "description": "Bad input. {\"ok\":false,\"error\":\"...\"}"
     },
     "429": {
      "description": "Rate limited. Retry after the Retry-After header."
     }
    },
    "parameters": [
     {
      "name": "place",
      "in": "query",
      "required": true,
      "description": "City, IANA zone or abbreviation, e.g. \"London\" or \"America/Phoenix\".",
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "year",
      "in": "query",
      "required": false,
      "description": "Year to list clock changes for. Default this year.",
      "schema": {
       "type": "integer"
      }
     }
    ]
   },
   "post": {
    "operationId": "zone_info_post",
    "summary": "Offset, abbreviation and daylight saving changes for a zone",
    "description": "Use to answer \"what is the UTC offset of X\", \"does X observe daylight saving\" and \"when do the clocks change\". Returns the current offset and abbreviation, whether the place observes DST, every clock change in the year with exact local before and after times, and the next change.",
    "x-full-description": "Use to answer \"what is the UTC offset of X\", \"does X observe daylight saving\" and \"when do the clocks change\". Returns the current offset and abbreviation, whether the place observes DST, every clock change in the year with exact local before and after times, and the next change. Abbreviations like IST or CST are ambiguous, so the answer says which zone was used. Returns: {place, zone, now:{local, utc_offset, abbreviation}, observes_dst, year, transitions:[{utc, local_before, local_after, offset_before, offset_after, change_minutes, kind}], next_transition, summary}",
    "x-openai-isConsequential": false,
    "responses": {
     "200": {
      "description": "Result. Always has \"ok\": true.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean"
          }
         },
         "additionalProperties": true
        }
       }
      }
     },
     "400": {
      "description": "Bad input. {\"ok\":false,\"error\":\"...\"}"
     },
     "429": {
      "description": "Rate limited. Retry after the Retry-After header."
     }
    },
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "place": {
          "type": "string",
          "minLength": 1,
          "maxLength": 60,
          "description": "City, IANA zone or abbreviation, e.g. \"London\" or \"America/Phoenix\"."
         },
         "year": {
          "type": "integer",
          "minimum": 1970,
          "maximum": 2100,
          "description": "Year to list clock changes for. Default this year."
         }
        },
        "required": [
         "place"
        ]
       }
      }
     }
    }
   }
  }
 },
 "externalDocs": {
  "description": "llms.txt",
  "url": "https://meridian.clawhard.com/llms.txt"
 }
}