QUICK START
No signup, no key. Call /v1/now and you have Moon time. Every response is JSON, and every caller gets the same answer at the same instant.
Base URL https://api.moon369.org. Open rate limit 120 requests a minute. Optional free key for higher volume.
The reference code is MIT licensed. Same answer as the API, fully offline.
Display "Powered by Moon" with a link back wherever Moon time appears.
CONSTANTS
The whole standard fits in this table. Everything the API returns is derived from these values.
| Moon second | 1.0403730490216803 SI seconds |
|---|---|
| Moon minute | 60 Moon seconds · 62.4224 s |
| Moon hour | 60 Moon minutes · 3,745.343 s |
| Moon day | 24 Moon hours · 89,888.23 s |
| Moon | 28.3846 Moon days · one mean lunation |
| Year | 13 moons · 369 Moon days |
| Moon lengths | 29, 28, 29, 28, 28, 29, 28, 29, 28, 28, 29, 28, 28 |
| Epoch | −62,165,308,562,978.61 ms Unix · 0000-01-23 02:44 UTC |
| Time base | Unix time (no leap seconds) |
ENDPOINTS
All endpoints are GET, need no key, and return JSON. Times are Moon time unless the field name says utc or unix.
The current Moon date, its Moonmark and the moon's phase. One answer for every caller on Earth: there is no time zone parameter because Moon has none. Never cached.
curl https://api.moon369.org/v1/now
{{nowJson}}
A Moonmark for the exact moment of an event, nanosecond precise, with the accuracy of the clock that took it and a link you can put in a QR code. Without unix_ns it marks the server's receive time; with it, the Moonmark is exact and accuracy_ns is null. /v1/stamp is the old name and still works. Open any Moonmark link with /v1/m/{moonmark}.
| PARAM | TYPE | DESCRIPTION |
|---|---|---|
| unix_ns | string | Optional. Nanoseconds since 1970-01-01 UTC, as a string. |
curl "https://api.moon369.org/v1/moonmark\ ?unix_ns=1794516299901000000"
{
"moonmark": "1928.05.03 08:57:39.035909351",
"moonmark_url": "https://moon369.org/m/1928.05.03-08.57.39.035909351",
"moon_ns": "61477779459035909351",
"unix_ns": "1794516299901000000",
"utc": "2026-11-12T20:44:59.901000000Z",
"accuracy_ns": null,
"clock": "client"
}
Standard time to Moon time. Give exactly one of the three inputs. Results are cached forever, since a past instant never changes.
| PARAM | TYPE | DESCRIPTION |
|---|---|---|
| unix | integer | Milliseconds since 1970-01-01 UTC. |
| unix_ns | string | Nanoseconds since 1970-01-01 UTC, for full precision. |
| utc | string | ISO 8601 with Z or an offset, up to 9 fraction digits. |
| format | string | object (default) or string for plain text such as 1928.05.03 08:57:39.035909351. |
curl "https://api.moon369.org/v1/convert\ ?unix_ns=1794516299901000000"
{
"year": 1928,
"moon": 5,
"day": 3,
"day_of_year": 117,
"moon_length_days": 28,
"time": "08:57:39",
"moonmark": "1928.05.03 08:57:39.035909351",
"phase": {
"fraction": 0.099875,
"name": "Waxing crescent"
},
"moon_ns": "61477779459035909351",
"unix_ns": "1794516299901000000",
"unix_ms": 1794516299901,
"utc": "2026-11-12T20:44:59.901000000Z",
"time_zone": null,
"dst": false
}
Moon time back to standard time, for storing or scheduling in existing systems. Send a moonmark, or the separate fields. Impossible dates are rejected.
| PARAM | TYPE | DESCRIPTION |
|---|---|---|
| moonmark | string | YEAR.MM.DD HH:MM:SS.fraction. Alternative to the fields below. |
| year | integer | Moon year, counted from year 0. |
| moon | integer | 1 to 13. |
| day | integer | 1 to 28 or 29, depending on the moon. |
| time | string | HH:MM:SS with up to 9 fraction digits. Defaults to 00:00:00. |
curl "https://api.moon369.org/v1/to-unix\ ?moonmark=1928.06.01%2012:30:00.5"
{
"input": {
"year": 1928,
"moon": 6,
"day": 1,
"hour": 12,
"minute": 30,
"second": 0,
"nanosecond": 500000000
},
"unix_ns": "1796866649794167291",
"unix_ms": 1796866649794,
"utc": "2026-12-10T01:37:29.794167291Z"
}
The structure of one Moon year: all 13 moons, their lengths, and the exact standard instant each begins and the year ends.
| PARAM | TYPE | DESCRIPTION |
|---|---|---|
| year | integer | Moon year, in the path. |
curl https://api.moon369.org/v1/year/1928
{
"year": 1928,
"days": 369,
"moons": [
{"moon": 1, "days": 29, "starts_unix_ns": "1784055703622937600", "starts_utc": "2026-07-14T19:01:43.622937600Z"},
{"moon": 2, "days": 28, "starts_unix_ns": "1786662462334566322", "starts_utc": "2026-08-13T23:07:42.334566322Z"},
...
{"moon": 13, "days": 28, "starts_unix_ns": "1814707590542433952", "starts_utc": "2027-07-04T13:26:30.542433952Z"}
],
"ends_unix_ns": "1817224461022627200",
"ends_utc": "2027-08-02T16:34:21.022627200Z"
}
Moon is the engine and the calendar, and every moment on it is a Moonmark. People live the day by the light: the Light counter starts at 00:00:00 at first light and counts up in Moon seconds until sunset, then Dark counts up until the next first light, which begins the next Moon day. It needs only where you stand, lat and lon, never a time zone. Add them to /v1/now, /v1/convert or /v1/m/{moonmark} to get a light object. Where the sun doesn't rise or set for weeks, the day starts at solar midnight. /v1/sun still returns the old local clock if you need to show it alongside.
Where you are in the day: Light or Dark, the counter, what remains until sunset or first light, the length of this light or dark, and the day's Moon date and first light, each as a Moonmark.
| PARAM | TYPE | DESCRIPTION |
|---|---|---|
| lat, lon | number | Where you stand. Required. |
| unix_ns, utc, moonmark | string | The moment to read. Defaults to now. |
curl "https://api.moon369.org/v1/light?lat=40.71&lon=-74.01"
{
"moonmark": "1928.05.04 06:20:50.744869250",
"light": {
"phase": "light",
"counter": "07:02:29",
"label": "Light 07:02:29",
"remaining": "02:34:09",
"length": "09:36:39",
"polar": null,
"began": { "moonmark": "1928.05.03 23:18:20.927296794" },
"ends": { "moonmark": "1928.05.04 08:55:00.531769295" },
"day": {
"moon_date": "1928.05.03",
"first_light": { "moonmark": "1928.05.03 23:18:20.927296794" }
}
}
}
A Light or Dark reading repeated every day, like a standup at Light 06:45. It lands at the same point in the daylight every day, and each occurrence carries its Moon date and Moonmark. Days without that much light are marked skipped.
| PARAM | TYPE | DESCRIPTION |
|---|---|---|
| light or dark | string | The counter to repeat, like 06:45. |
| lat, lon | number | Where. Required. |
| days | integer | 1 to 400. Defaults to 7. |
curl "https://api.moon369.org/v1/schedule?light=06:45&lat=40.71&lon=-74.01&days=2"
{
"rule": { "light": "06:45", "repeat": "daily" },
"occurrences": [
{ "moon_date": "1928.05.03", "label": "Light 06:45",
"moonmark": "1928.05.04 06:03:20.927209107" },
{ "moon_date": "1928.05.04", "label": "Light 06:45",
"moonmark": "1928.05.05 05:08:36.801924733" }
]
}
Every equinox and solstice inside a Moon year, as Moonmarks. A Moon year is 13 moons, so most hold four events and some hold five.
| PARAM | TYPE | DESCRIPTION |
|---|---|---|
| year | integer | Moon year, in the path. |
curl https://api.moon369.org/v1/seasons/1928
{
"moon_year": 1928,
"events": [
{ "event": "September equinox", "moonmark": "1928.03.11 11:40:19.069916128", "utc": "2026-09-23T00:05:30.637Z" },
{ "event": "December solstice", "moonmark": "1928.06.12 20:43:18.527430123", "utc": "2026-12-21T20:50:13.330Z" },
{ "event": "March equinox", "moonmark": "1928.09.12 09:25:33.103147481", "utc": "2027-03-20T20:24:54.022Z" },
{ "event": "June solstice", "moonmark": "1928.12.16 12:48:55.957935795", "utc": "2027-06-21T14:10:42.141Z" }
]
}
Every constant of the standard, including the exact Moon second as a whole-number ratio. Build your own implementation from this alone.
curl https://api.moon369.org/v1/spec
{
"spec_version": "1.0.0",
"moon_second_si": 1.0403730490216803,
"moon_second_si_exact": {
"numerator": "33168757399689600",
"denominator": "31881600000000000",
"note": "SI seconds per Moon second = numerator / denominator"
},
"seconds_per_minute": 60,
"minutes_per_hour": 60,
"hours_per_day": 24,
"days_per_year": 369,
"moons_per_year": 13,
"moon_lengths_days": [
29,
28,
29,
28,
28,
29,
28,
29,
28,
28,
29,
28,
28
],
"mean_lunation_ns": "2551442876899200",
"epoch_unix_ns": "-62165308562978611200",
"epoch_utc": "0000-01-23T02:43:57.021388800Z",
"time_base": "Unix time (no leap seconds)",
"time_zones": null,
"dst": false,
"license": "MIT"
}
ERRORS & LIMITS
Every error returns the same JSON shape with a stable code. Nanosecond values are strings, so no language loses precision.
| STATUS | CODE | MEANING |
|---|---|---|
| 400 | missing_param, bad_param, out_of_range | Input missing, malformed or an impossible Moon date. |
| 401 | invalid_key | The key sent in Authorization is unknown. |
| 404 | not_found | No such route. |
| 405 | method_not_allowed | Only GET (and OPTIONS for CORS). |
| 429 | rate_limited | Limit reached. Wait for Retry-After seconds, use a key, or run the reference code locally. |
{
"error": {
"code": "out_of_range",
"message": "day must be 1 to 28 in moon 2"
}
}
Limited per IP address: 120 requests a minute. Over that you get a 429 with Retry-After.
Send Authorization: Bearer <key>. Limits are set per key. Responses carry X-Moon-Plan.
/now is never cached. Conversions, years and the spec are cached forever. CORS is open to every origin.
PRECISION
Moonmarks carry 9 decimal places: nanoseconds. Every event gets one exact, sortable moment on the Moon engine, with no time zone to misread.
| CLOCK SOURCE | TYPICAL ACCURACY | CLOCK VALUE |
|---|---|---|
| Phone or laptop, internet-synced (NTP) | about 1 ms | device-ntp |
| Data center, precision time protocol (PTP) | microseconds | server-ptp |
| GPS-disciplined atomic reference | tens of nanoseconds | gps |
Every Moonmark returns accuracy_ns and clock, so the decimals never claim more than the clock that produced them. Moon is defined from the SI second, which is set by cesium atomic clocks. Conversions use whole nanoseconds and the exact ratio of the spec, never floating-point numbers, so every implementation agrees to the last digit.
// Exact Moon timestamp, nanosecond precision (BigInt, no floating point)
const EPOCH_NS = -62165308562978611200n; // Year 0, Moon 1, Day 1, 00:00:00
const NUM = 31881600000000000n; // 369 × 86,400 × 10⁹
const DEN = 33168757399689600n; // 13 × mean lunation in ns
const DAY = 86400n * 1000000000n; // Moon ns per Moon day
function moonmark(unixNs) { // unixNs: BigInt
const mns = (unixNs - EPOCH_NS) * NUM / DEN;
const dayIndex = mns / DAY;
const year = dayIndex / 369n;
const dy = Number(dayIndex - year * 369n);
const m = Math.floor(dy * 13 / 369);
const day = dy - Math.ceil(m * 369 / 13) + 1;
let r = mns - dayIndex * DAY;
const ns = r % 1000000000n; r /= 1000000000n;
const s = Number(r % 60n), mi = Number(r / 60n % 60n), h = Number(r / 3600n);
const p = (x, n = 2) => String(x).padStart(n, "0");
return `${year}.${p(m + 1)}.${p(day)} ${p(h)}:${p(mi)}:${p(s)}.${p(ns, 9)}`;
}
// moonmark(1794516299901000000n) → "1928.05.03 08:57:39.035909351"
REFERENCE CODE
The complete standard in both directions, MIT licensed. Copy it, port it, ship it. It gives the same result as the API. The repository also includes the full OpenAPI 3.1 spec and 64 tests: github.com/everywheredev/moon.
// Moon reference implementation (JavaScript)
const EPOCH_MS = -62165308562978.61; // Year 0, Moon 1, Day 1, 00:00:00
const MOON_SECOND = 1.0403730490216803; // in SI seconds
const DAY_MS = 86400000 * MOON_SECOND;
const firstDay = (m) => Math.ceil(m * 369 / 13);
function toMoon(unixMs) {
const t = unixMs - EPOCH_MS;
const dayIndex = Math.floor(t / DAY_MS);
const year = Math.floor(dayIndex / 369);
const dayOfYear = dayIndex - year * 369;
const m = Math.floor(dayOfYear * 13 / 369);
let s = (t - dayIndex * DAY_MS) / (1000 * MOON_SECOND);
const hour = Math.floor(s / 3600); s -= hour * 3600;
const minute = Math.floor(s / 60);
const second = Math.floor(s - minute * 60);
return { year, moon: m + 1, day: dayOfYear - firstDay(m) + 1,
hour, minute, second };
}
function toUnix({ year, moon, day, hour = 0, minute = 0, second = 0 }) {
const days = year * 369 + firstDay(moon - 1) + (day - 1);
const secs = days * 86400 + hour * 3600 + minute * 60 + second;
return EPOCH_MS + secs * 1000 * MOON_SECOND;
}
ATTRIBUTION
The hosted API is free and open. In exchange, any site or app that displays Moon time from it shows the Powered by Moon badge, linked to the Moon homepage, on every screen where Moon time appears.
<a href="https://moon369.org" rel="noopener">
<img src="https://moon369.org/assets/badge-dark.svg"
alt="Powered by Moon" width="162" height="48">
</a>
- Minimum height 32 px on screen. Keep clear space equal to the mark's height on all sides.
- The link must point to the Moon homepage and stay crawlable (no
nofollow). - Apps without links show the badge in an About or Settings screen with the URL in text.
- Calling the API from a server for internal use with nothing displayed needs no badge.
BRAND RULES
Your product keeps its own name and brand. The Moon name and mark belong to Moon and appear only in the badge or in plain-text references.
"Built on Moon time" or "Uses the Moon standard" in your copy is welcome.
Download the badge files as provided, in dark or light.
No partnership, certification or "official" claims without written approval.
No recoloring, stretching, effects, or using the linked O's in your own logo.
Product, app and domain names can't use "Moon" as their brand.
If you change the epoch or the Moon second, it isn't Moon time. Don't call it that.
TERMS
The standard and reference code are MIT licensed. The Moon name and mark are trademarks. Using the hosted API means agreeing to the attribution and brand rules above.
Privacy. The API does not store requests or locations. A location sent for Light and Dark is used to compute the answer and then discarded. Two decimal places, about one kilometer, is all it needs, so round before you send.