A REST + GraphQL API for interplanetary time, work schedules, and meeting planning.
Server: node api.js ·
Default port: 3001 ·
Base URL: http://localhost:3001/api
node api.js # start the server
# REST — JSON
curl -s http://localhost:3001/api?action=planet_time&planet=mars | python3 -m json.tool
# REST — POST JSON
curl -s -X POST http://localhost:3001/api \
-H 'Content-Type: application/json' \
-d '{"action":"planet_time","planet":"mars"}' | python3 -m json.tool
# GraphQL
curl -s -X POST http://localhost:3001/api \
-H 'Content-Type: application/graphql' \
-d 'query { planetTime(planet:"mars") { hour minute isWorkHour dowName } }' \
| python3 -m json.tool
# next_meeting_slot — AI agent style
curl -s -X POST http://localhost:3001/api \
-H 'Content-Type: application/json' \
-d '{
"action": "next_meeting_slot",
"locations": [
{"type":"earth","tz":"America/New_York","label":"New York"},
{"type":"earth","tz":"Europe/London","label":"London"},
{"type":"planet","planet":"mars","label":"Mars Base"}
],
"maxOptions": 3
}'
Single endpoint for all actions. Accepts JSON body, GraphQL body, or GET query-string.
Get current (or specified) local time for any planet.
| Param | Type | Description |
|---|---|---|
| planet | string | mercury, venus, mars, jupiter, saturn, uranus, neptune |
| date opt | ISO-8601 | UTC datetime. Defaults to now. |
Find overlapping work windows between two planets (two-body variant).
| Param | Type | Description |
|---|---|---|
| from | string | Planet key (e.g. "earth") |
| to | string | Planet key (e.g. "mars") |
| days opt | int | Search window (Earth days). Default 7. |
| start opt | ISO-8601 | Search from this UTC time. Default now. |
Find the next N available meeting slots across any mix of Earth cities and planets. Returns multiple options with per-location local times — designed for AI agents.
| Param | Type | Description |
|---|---|---|
| locations | array | Array of location objects (see below) |
| from opt | ISO-8601 | Start searching from. Default now. |
| maxDays opt | int | Days to scan. Default 14. |
| stepMinutes opt | int | Resolution. Default 30. |
| minDurationMinutes opt | int | Minimum overlap. Default 30. |
| maxOptions opt | int | Options to return. Default 3. |
| Field | Type | Description |
|---|---|---|
| type | "earth" | "planet" | Required |
| tz *earth | string | IANA timezone, e.g. "America/New_York" |
| workWeek opt | string | mon-fri, sun-thu, sat-thu, mon-sat |
| workStart opt | int | Work start local hour (0–23). Default 9. |
| workEnd opt | int | Work end local hour (0–23). Default 17. |
| planet *planet | string | Planet key, e.g. "mars" |
| tzOffset opt | number | Planet local-hour offset from prime meridian. Default 0. |
| label opt | string | Display name in results |
Light-speed travel time between two solar-system bodies.
| Param | Type | Description |
|---|---|---|
| from | string | Body key (e.g. "earth") |
| to | string | Body key (e.g. "mars") |
| date opt | ISO-8601 | UTC datetime. Default now. |
query {
planetTime(planet: "mars", date: "2026-02-20T12:00:00Z") {
hour minute isWorkHour dowName formatted
}
}
query {
nextMeetingSlot(
locations: [
{type: "earth", tz: "America/New_York", label: "New York"},
{type: "planet", planet: "mars", label: "Mars Base"}
]
maxOptions: 3
) {
found message
slots { startIso endIso durationMinutes
localTimes { label timeStr isWorkHour } }
}
}
query {
lightTravel(from: "earth", to: "mars") {
oneWaySeconds oneWayFormatted roundTripFormatted
}
}
The next_meeting_slot action is designed for AI scheduling agents:
{
"action": "next_meeting_slot",
"locations": [
{ "type": "earth", "tz": "America/Chicago", "label": "Houston" },
{ "type": "earth", "tz": "Europe/Berlin", "label": "Berlin" },
{ "type": "planet","planet": "mars", "label": "Mars Base Alpha" }
],
"maxOptions": 5,
"minDurationMinutes": 60
}
// Response shape — present to user as "Here are your options:"
{
"found": true,
"message": "Found 3 option(s) within 14 days.",
"slots": [
{
"startIso": "2026-02-23T14:00:00.000Z",
"endIso": "2026-02-23T17:00:00.000Z",
"durationMinutes": 180,
"localTimes": [
{ "label": "Houston", "timeStr": "Mon 08:00", "isWorkHour": true },
{ "label": "Berlin", "timeStr": "Mon 15:00", "isWorkHour": true },
{ "label": "Mars Base Alpha","timeStr": "12:34 Arisian", "isWorkHour": true }
]
},
...
]
}
Earth city work-hour checks use Intl.DateTimeFormat with full
IANA timezone strings (e.g. "America/New_York",
"Europe/London"). Node.js bundles the complete IANA tzdata, so
DST transitions are applied automatically for every location — no manual
offset calculation needed.
Example: on 8 Mar 2026 at 06:30 UTC, New York is in EST (UTC−5, 01:30 — outside work hours). After the DST switch (clocks spring forward), the same UTC moment in summer is EDT (UTC−4). The API always returns the correct local wall-clock time and work-hour status for any date.
// Ask for New York work-hour status just before and just after DST spring-forward
// (US DST 2026: clocks spring forward Sun 8 Mar at 02:00 → 03:00)
{"action":"next_meeting_slot",
"locations":[{"type":"earth","tz":"America/New_York","label":"NY"}],
"from":"2026-03-08T06:00:00Z"}
The server is designed to add bearer-token auth with minimal changes. When enabled:
Authorization: Bearer <your-api-key>
Contact the operator for API keys. Rate limits and usage quotas will be enforced per token.