Skip to content
Public Beta Docs

TimeNowHub API

The Phase 3 API is still intentionally compact: one stable dataset, three beta workflow endpoints, explicit guardrails, and internal routes that stay documented without being marketed as durable public guarantees.

Published January 15, 2026 Reviewed April 7, 2026 Auth none

Quickstart

1. Resolve slugs

Pull /api/cities once, cache it, and use the public slug as your stable key.

2. Fetch live data

Call /api/time/:city, /api/compare/:city1/:city2, /api/availability, /api/query, or /api/handoff depending on whether you need a clock, overlap, parser answer, or async estimate.

3. Respect beta guardrails

Honor rate limits, expect additive fields during beta, and do not turn internal SEO routes into hard dependencies.

Contract Status

Stable

Safe for public dataset access. We expect additive evolution, not routine churn.

Beta

Useful now for real integrations, but response shapes can still improve before a GA contract.

Internal

Exposed for transparency and internal alignment, not as a public compatibility promise.

GET stable /api/cities

Returns the public city dataset with slugs, IANA timezone IDs, country labels, coordinates, and population data.

Auth
none
Cache
public, max-age=300
Notes
Best starting point for any integration. Cache aggressively and use the public slug as your stable key.
Response Example (JSON)
{
  "status": "stable",
  "auth": "none",
  "generatedAt": "2026-04-07T10:30:00.000Z",
  "cities": [
    {
      "name": "Tokyo",
      "slug": "tokyo",
      "timezone": "Asia/Tokyo",
      "country": "Japan",
      "lat": 35.6762,
      "lng": 139.6503,
      "population": 37274000
    }
  ]
}
GET beta /api/time/:city

Returns current local time, UTC offset, DST status, holiday coverage availability, and the current business-hours label for one city.

Auth
none
Cache
public, max-age=60
Notes
Useful for extension popups, “what time is it now?” cards, and lightweight embeds.
Response Example (JSON)
{
  "status": "beta",
  "auth": "none",
  "contract": "beta",
  "generatedAt": "2026-04-07T10:30:00.000Z",
  "city": {
    "name": "Tokyo",
    "slug": "tokyo",
    "country": "Japan",
    "timezone": "Asia/Tokyo",
    "currentTime": "19:30",
    "currentDate": "2026-04-07",
    "offsetNameShort": "GMT+9",
    "utcOffset": "UTC+09:00",
    "isInDST": false,
    "holidayCoverageAvailable": true,
    "businessStatus": {
      "status": "Evening",
      "reason": "Outside Business Hours"
    }
  }
}
GET beta /api/compare/:city1/:city2

Returns current pair guidance including overlap quality, next-better-window hints, async risk, and current city statuses.

Auth
none
Cache
public, max-age=60
Notes
Good for pair pages, quick “can these teams talk now?” checks, and internal tooling that wants human-readable guidance.
Response Example (JSON)
{
  "status": "beta",
  "auth": "none",
  "contract": "beta",
  "generatedAt": "2026-04-07T10:30:00.000Z",
  "routeMode": "dynamic",
  "comparison": {
    "pair": "london:new-york",
    "title": "Best Time to Call London from New York",
    "answer": "London and New York usually have a strong live-call window.",
    "summary": "Current overlap is good for meetings during the late London afternoon and late New York morning.",
    "callScore": 8,
    "asyncRisk": "low",
    "overlapWindow": "13:00-17:00 London / 08:00-12:00 New York"
  }
}
GET beta /api/availability?cities=london,new-york,tokyo&offset=1.5&duration=60

Returns a multi-city planner snapshot with call score, focus bands, awake/working counts, city states, and next-better-window guidance.

Auth
none
Cache
public, max-age=60
Notes
Supports up to 8 cities per call. This is the public beta endpoint for planner snapshots and embedded meeting-window cards.
Response Example (JSON)
{
  "status": "beta",
  "auth": "none",
  "contract": "beta",
  "generatedAt": "2026-04-07T10:30:00.000Z",
  "requestedOffsetHours": 1.5,
  "durationMinutes": 60,
  "cities": [
    { "name": "London", "slug": "london", "timezone": "Europe/London", "country": "United Kingdom" }
  ],
  "snapshot": {
    "callScore": 7.8,
    "scoreLabel": "Usable live window",
    "availabilityStatus": "good",
    "workingCount": 2,
    "sleepingCount": 1
  }
}
GET beta /api/query?text=What%20time%20is%20it%20in%20London%3F

Parses a supported natural-language scheduling question into a deterministic answer, evidence set, and matching route.

Auth
none
Cache
public, max-age=60
Notes
Built for repeatable question shapes rather than open-ended chat. Supports direct current-time lookups, conversions, meeting prompts, DST checks, EOD checks, and handoff questions.
Response Example (JSON)
{
  "status": "beta",
  "auth": "none",
  "contract": "beta",
  "generatedAt": "2026-04-07T10:30:00.000Z",
  "result": {
    "intent": "current-time",
    "answer": "It is 11:30 in London right now.",
    "destination": "/time/london"
  }
}
GET beta /api/handoff?recipient=tokyo&from=london&sentAt=2026-04-07T13:00:00Z

Estimates when a teammate is likely to see and act on a cross-region message.

Auth
none
Cache
public, max-age=60
Notes
Supports sender and recipient city slugs plus optional workday controls. This is an estimate layer, not a delivery guarantee.
Response Example (JSON)
{
  "status": "beta",
  "auth": "none",
  "contract": "beta",
  "prediction": {
    "priority": "next-open",
    "likelySeenLabel": "Tue, Apr 7 · 09:15",
    "likelyActionLabel": "Tue, Apr 7 · 10:30"
  }
}
POST beta /api/integrations/slack/command?text=Best%20time%20for%20a%20meeting%20between%20New%20York,%20London,%20and%20Tokyo.

Formats a deterministic time query into Slack-friendly JSON with text and blocks.

Auth
none
Cache
public, max-age=60
Notes
Designed for slash commands and lightweight workflow bots. Accepts Slack-style POST form payloads and GET query text for quick browser tests.
Response Example (JSON)
{
  "response_type": "ephemeral",
  "text": "The strongest live window scores 7.8/10..."
}
GET beta /api/integrations/google-calendar/link?title=Weekly%20Ops%20Sync&cities=london,new-york,tokyo&start=2026-04-07T13:00:00Z&duration=60

Returns a Google Calendar draft URL for a planner-approved meeting slot.

Auth
none
Cache
public, max-age=300
Notes
Use this when you want a stateless booking handoff without generating an ICS file first.
Response Example (JSON)
{
  "status": "beta",
  "auth": "none",
  "contract": "beta",
  "url": "https://calendar.google.com/calendar/render?..."
}
GET internal /api/seo/:city

Internal page-generation contract for city SEO metadata.

Auth
none
Cache
public, max-age=60
Notes
Documented for transparency. Do not build external guarantees on this route.
Response Example (JSON)
{
  "title": "Time in Tokyo Now...",
  "description": "Current local time in Tokyo...",
  "jsonLd": { "@type": "Place" }
}

curl

curl https://timenowhub.com/api/cities
curl https://timenowhub.com/api/time/tokyo
curl https://timenowhub.com/api/compare/london/new-york
curl "https://timenowhub.com/api/availability?cities=london,new-york,tokyo&offset=1.5&duration=60"
curl "https://timenowhub.com/api/query?text=What%20time%20is%20it%20in%20London%3F"
curl "https://timenowhub.com/api/handoff?recipient=tokyo&from=london&sentAt=2026-04-07T13:00:00Z"

JavaScript

const response = await fetch(
  'https://timenowhub.com/api/query?text=Best%20time%20for%20a%20meeting%20between%20New%20York,%20London,%20and%20Tokyo.'
);

if (!response.ok) {
  throw new Error('TimeNowHub query request failed');
}

const payload = await response.json();
console.log(payload.result.intent);
console.log(payload.result.answer);

Python

import requests

response = requests.get(
    'https://timenowhub.com/api/handoff?recipient=tokyo&from=london',
    timeout=10,
)
response.raise_for_status()
payload = response.json()

print(payload['prediction']['likelySeenLabel'])
print(payload['prediction']['priority'])

Guardrails

All public routes are unauthenticated right now. Headers explicitly advertise auth = none so clients do not over-assume.

The current limit is 100 requests per minute per IP. Expect stricter tiers before GA if public demand grows.

Availability requests are capped at 8 cities, offsets must stay within +/-24 hours, and durations must stay between 15 and 240 minutes.

Query parsing is intentionally deterministic. If the question shape is unsupported, the API returns examples instead of inventing an answer.

Slack slash-command integrations should use POST form payloads, but GET remains available for quick manual testing and linkable demos.

Use IANA timezone identifiers from the dataset and expect DST shifts. Do not hardcode UTC offsets beyond the moment you fetched.

Internal SEO routes are visible for transparency but are not part of the public compatibility promise.

Failure Handling

Public errors return a structured envelope with status = error and an error.code. Treat 400-series responses as invalid input or quota issues, and refresh your city slug map when a city lookup fails.

Launch Surfaces