CORS-open public endpoint. The no-code embed widget is free and keyless; raw JSON integrations use a free API key (1,000 requests/day). Built for embedding TimeZoneMeet conversions in your own app.
This is the live widget. ↙
Powered by the same /api/convert endpoint documented below. Paste two lines to put it on your own dashboard — no key, no build step.
GEThttps://timezonemeet.app/api/convert
Converts a UTC instant into one or more IANA time zones. Returns the local wall-clock time, the same instant as a zoned ISO-8601 string, the UTC offset, the day of the week, and a DST flag for each zone.
Two ways to use the API:
/api/convert — needs a free API key. Get one in ~30 seconds (email verification, no card). Free tier: 1,000 requests/day per key, plus a short per-minute burst cap.Pass your key any one of these ways:
# Header (recommended) curl 'https://timezonemeet.app/api/convert?utc=now&tz=Europe/Paris' \ -H 'X-API-Key: tzm_live_xxxxxxxx' # Authorization: Bearer curl 'https://timezonemeet.app/api/convert?utc=now&tz=Europe/Paris' \ -H 'Authorization: Bearer tzm_live_xxxxxxxx' # Query parameter (handy for quick tests; avoid in logs) curl 'https://timezonemeet.app/api/convert?utc=now&tz=Europe/Paris&key=tzm_live_xxxxxxxx'
Keyless calls to /api/convert still work today (the widget uses that path) but are rate-limited and intended for the widget — production raw-data integrations should use a key. When you display the data, keep the attribution (see Terms).
| Name | Required | Description |
|---|---|---|
utc |
Yes |
ISO-8601 UTC timestamp, e.g. 2026-05-20T14:00:00Z (the trailing Z is required when using a literal timestamp).
You may also pass the string now to convert the current instant.
|
tz |
Yes |
IANA time-zone identifier, e.g. Europe/Paris, America/Los_Angeles, Asia/Kolkata.
Pass a comma-separated list (max 10) for multiple zones in a single request: Europe/Paris,Asia/Tokyo,UTC.
|
JSON. Always returns { utc, results, provider, url, attribution } with one entry in results per zone you passed, in the order you passed them. The provider/url/attribution fields identify the data source — please surface the attribution where you display the data (see Terms).
{
"utc": "2026-05-20T14:00:00.000Z",
"provider": "TimeZoneMeet",
"url": "https://timezonemeet.app",
"attribution": "Times by TimeZoneMeet — https://timezonemeet.app",
"results": [
{
"timezone": "Europe/Paris",
"localTime": "2026-05-20 16:00",
"iso": "2026-05-20T16:00:00+02:00",
"offset": "+02:00",
"offsetMinutes": 120,
"abbreviation": "CEST",
"dayOfWeek": "Wednesday",
"isDst": true
},
{
"timezone": "Asia/Kolkata",
"localTime": "2026-05-20 19:30",
"iso": "2026-05-20T19:30:00+05:30",
"offset": "+05:30",
"offsetMinutes": 330,
"abbreviation": "GMT+5:30",
"dayOfWeek": "Wednesday",
"isDst": false
}
]
}
| Field | Type | Notes |
|---|---|---|
utc | string | The instant you requested, normalized to ISO-8601 with milliseconds. Echoes the resolved value when you passed now. |
provider / url | string | The data source (TimeZoneMeet) and its URL. Display the attribution where you show the data. |
attribution | string | Ready-made attribution string: Times by TimeZoneMeet — https://timezonemeet.app. |
results[].timezone | string | The IANA zone you asked for, echoed back. |
results[].localTime | string | Wall-clock time formatted as YYYY-MM-DD HH:MM (24-hour). Truncated to the minute. |
results[].iso | string | The same instant rendered as a zoned ISO-8601 string, including seconds and the offset suffix (e.g. 2026-05-20T16:00:00+02:00). |
results[].offset | string | Offset from UTC at this instant, formatted ±HH:MM. Correctly handles half-hour and 45-minute zones (India, Nepal, etc.). |
results[].offsetMinutes | number | Same offset as a signed integer in minutes. Useful if you'd rather not parse the string. |
results[].abbreviation | string | The zone's short name at this instant (e.g. EST, PDT). Best-effort: some Node/browser engines return GMT+5:30-style strings here instead of a regional abbreviation. |
results[].dayOfWeek | string | English day name in the target zone (Monday, Tuesday, …). |
results[].isDst | boolean | true if the zone is observing summer time at this instant. false for zones that don't observe DST. |
curl 'https://timezonemeet.app/api/convert?utc=2026-05-20T14:00:00Z&tz=Europe/Paris'
Multiple zones in one call:
curl 'https://timezonemeet.app/api/convert?utc=2026-05-20T14:00:00Z&tz=Europe/Paris,Asia/Tokyo,America/New_York'
Right now, in your local zone:
curl 'https://timezonemeet.app/api/convert?utc=now&tz=America/Los_Angeles'
const url = new URL("https://timezonemeet.app/api/convert");
url.searchParams.set("utc", "2026-05-20T14:00:00Z");
url.searchParams.set("tz", "Europe/Paris,Asia/Tokyo");
const res = await fetch(url);
const data = await res.json();
for (const r of data.results) {
console.log(`${r.timezone}: ${r.localTime} (${r.offset}, ${r.dayOfWeek})`);
}
// Europe/Paris: 2026-05-20 16:00 (+02:00, Wednesday)
// Asia/Tokyo: 2026-05-20 23:00 (+09:00, Wednesday)
import requests
r = requests.get(
"https://timezonemeet.app/api/convert",
params={"utc": "2026-05-20T14:00:00Z", "tz": "Europe/Paris,Asia/Tokyo"},
timeout=5,
)
r.raise_for_status()
for entry in r.json()["results"]:
print(entry["timezone"], entry["localTime"], entry["offset"])
If you just want a live world-clock panel on your own dashboard without writing any fetch/render code, drop in the
embeddable widget. It calls the /api/convert endpoint above for you, renders one row per zone, and ticks
every minute. No build step, no dependencies, no API key.
Paste a container plus the script anywhere on your page:
<div data-tzm-clock
data-zones="America/New_York,Europe/London,Asia/Tokyo"></div>
<script src="https://timezonemeet.app/embed.js" async></script>
That renders:
New York 09:00 Mon London 14:00 Mon Tokyo 23:00 Mon
Add as many data-tzm-clock containers as you like — a single embed.js tag drives all of them.
Up to 10 zones per widget (same limit as the endpoint).
Configure each widget with data-* attributes on its container:
| Attribute | Description |
|---|---|
data-zones |
Required. Comma-separated IANA zones, in display order. Max 10. e.g. America/Los_Angeles,Europe/Paris,Asia/Kolkata. |
data-show |
Comma-separated extras, off by default:
offset appends the ±HH:MM UTC offset,
dst shows a DST badge when a zone is on summer time, and
utc prepends a UTC reference clock to the panel.
Combine them: data-show="offset,dst,utc".
|
data-labels |
Optional comma-separated labels overriding the auto-derived city names (must match data-zones order). e.g. data-labels="HQ (SF),Berlin Office,Bengaluru Team". |
Every widget shows a "Times by TimeZoneMeet" link back to the source. Attribution is required (see Terms), so there is no option to disable it.
The widget renders into your page (not an iframe), so it inherits your fonts and sits inside your layout. Every color and spacing value is a CSS custom property with a sensible default — scope overrides to the widget to match your dashboard:
<div data-tzm-clock
data-zones="America/New_York,Europe/London,Asia/Singapore"
data-show="offset,dst"
style="--tzm-clock-bg:#111827; --tzm-clock-fg:#f9fafb;
--tzm-clock-muted:#9ca3af; --tzm-clock-border:#1f2937;
--tzm-clock-accent:#8b5cf6;"></div>
Available properties: --tzm-clock-bg, --tzm-clock-fg, --tzm-clock-muted,
--tzm-clock-accent, --tzm-clock-border, --tzm-clock-radius, --tzm-clock-font.
/api/convert is unreachable, it falls back to the browser's own time-zone data so the clock still shows the correct time (the offset/DST extras may be omitted in that fallback).window.TZMClock.refresh() to render any new data-tzm-clock containers.Validation errors return HTTP 400; authentication/quota errors return 401/429. The body is always JSON { "error": "…" }.
| Status | Condition | Body |
|---|---|---|
401 | Unknown/invalid key | {"error":"invalid_api_key"} |
401 | Revoked key | {"error":"revoked_api_key"} |
429 | Over daily quota | {"error":"daily_quota_exceeded","limit":1000} |
429 | Burst limit | {"error":"rate_limited","retry_after":60} |
400 | utc missing | utc is required (ISO 8601 UTC timestamp like 2026-05-20T14:00:00Z, or 'now'). |
400 | utc unparseable | utc could not be parsed. Use ISO 8601 (e.g. 2026-05-20T14:00:00Z) or 'now'. |
400 | tz missing | tz is required (IANA zone, e.g. Europe/Paris). Multiple zones may be comma-separated. |
400 | Unknown zone in tz | Unknown IANA timezone: <zone you passed> |
400 | More than 10 zones | Maximum 10 zones per request. |
Responses are explicitly cacheable. For a fixed UTC instant the same zone always returns the same result, so the server sets:
Cache-Control: public, max-age=3600, s-maxage=2592000
That's 1 hour in the browser, 30 days in any shared CDN. If you pass utc=now, the response is marked no-store instead.
If you're building a high-traffic integration, prefer fixed timestamps and let your CDN absorb the bulk of the load. Asking for "now" 10 times a second per user is wasteful — compute "now" client-side, round to the minute or hour you actually need, then call with the fixed timestamp.
429 with {"error":"daily_quota_exceeded"}.private, no-store (so usage meters accurately); keyless responses stay cacheable.
Because keyless /api/convert responses are cacheable, the widget stays well under the limit by reusing CDN-cached responses. For
keyed integrations, prefer fixed timestamps and cache on your own side.
Need more than 1,000/day? Drop us a note at contact with your use case — we're happy to raise the limit for legitimate integrations.
The API ships a machine-readable OpenAPI 3.1 description:
GEThttps://timezonemeet.app/openapi.json
https://timezonemeet.app/openapi.json to generate a ready-to-run collection.
The tz parameter accepts any identifier that's valid in the IANA Time Zone Database.
Always prefer the canonical region/city form:
America/Los_Angeles, not PST or PDTEurope/London, not BST or GMTAsia/Kolkata, not IST
Three-letter abbreviations like EST, PST, and IST are ambiguous (IST means both Indian and Irish Standard Time, for example)
and many of them don't observe DST when callers expect them to. The TimeZoneMeet blog has
a longer post on why this matters.
attribution/url from the response near where you display the data, linking back to timezonemeet.app.