API
OPEN SOURCE · MIT · V1

MOON API

Moon is an open standard and open source. Call the hosted API with no signup, or run the reference code yourself. One constant, no time zones.

LIVE · MOONMARK · GET /v1/now
{{clock}}
{{dateLine}}
01

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.

STEP 1
Call the API

Base URL https://api.moon369.org. Open rate limit 120 requests a minute. Optional free key for higher volume.

STEP 2
Or run it yourself

The reference code is MIT licensed. Same answer as the API, fully offline.

STEP 3
Show the badge

Display "Powered by Moon" with a link back wherever Moon time appears.

02

CONSTANTS

The whole standard fits in this table. Everything the API returns is derived from these values.

Moon second1.0403730490216803 SI seconds
Moon minute60 Moon seconds · 62.4224 s
Moon hour60 Moon minutes · 3,745.343 s
Moon day24 Moon hours · 89,888.23 s
Moon28.3846 Moon days · one mean lunation
Year13 moons · 369 Moon days
Moon lengths29, 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 baseUnix time (no leap seconds)
03

ENDPOINTS

All endpoints are GET, need no key, and return JSON. Times are Moon time unless the field name says utc or unix.

GET /v1/now

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.

REQUEST
curl https://api.moon369.org/v1/now
RESPONSE200 OK
{{nowJson}}
GET /v1/moonmark

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}.

PARAMTYPEDESCRIPTION
unix_nsstringOptional. Nanoseconds since 1970-01-01 UTC, as a string.
REQUEST
curl "https://api.moon369.org/v1/moonmark\
  ?unix_ns=1794516299901000000"
RESPONSE200 OK
{
  "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"
}
GET /v1/convert

Standard time to Moon time. Give exactly one of the three inputs. Results are cached forever, since a past instant never changes.

PARAMTYPEDESCRIPTION
unixintegerMilliseconds since 1970-01-01 UTC.
unix_nsstringNanoseconds since 1970-01-01 UTC, for full precision.
utcstringISO 8601 with Z or an offset, up to 9 fraction digits.
formatstringobject (default) or string for plain text such as 1928.05.03 08:57:39.035909351.
REQUEST
curl "https://api.moon369.org/v1/convert\
  ?unix_ns=1794516299901000000"
RESPONSE200 OK
{
  "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
}
GET /v1/to-unix

Moon time back to standard time, for storing or scheduling in existing systems. Send a moonmark, or the separate fields. Impossible dates are rejected.

PARAMTYPEDESCRIPTION
moonmarkstringYEAR.MM.DD HH:MM:SS.fraction. Alternative to the fields below.
yearintegerMoon year, counted from year 0.
mooninteger1 to 13.
dayinteger1 to 28 or 29, depending on the moon.
timestringHH:MM:SS with up to 9 fraction digits. Defaults to 00:00:00.
REQUEST
curl "https://api.moon369.org/v1/to-unix\
  ?moonmark=1928.06.01%2012:30:00.5"
RESPONSE200 OK
{
  "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"
}
GET /v1/year/{year}

The structure of one Moon year: all 13 moons, their lengths, and the exact standard instant each begins and the year ends.

PARAMTYPEDESCRIPTION
yearintegerMoon year, in the path.
REQUEST
curl https://api.moon369.org/v1/year/1928
RESPONSE200 OK
{
  "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"
}
LIGHT · DARK · HOW PEOPLE LIVE THE DAY

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.

GET /v1/light LIGHT

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.

PARAMTYPEDESCRIPTION
lat, lonnumberWhere you stand. Required.
unix_ns, utc, moonmarkstringThe moment to read. Defaults to now.
REQUEST
curl "https://api.moon369.org/v1/light?lat=40.71&lon=-74.01"
RESPONSE200 OK
{
  "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" }
    }
  }
}
GET /v1/schedule SUN

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.

PARAMTYPEDESCRIPTION
light or darkstringThe counter to repeat, like 06:45.
lat, lonnumberWhere. Required.
daysinteger1 to 400. Defaults to 7.
REQUEST
curl "https://api.moon369.org/v1/schedule?light=06:45&lat=40.71&lon=-74.01&days=2"
RESPONSE200 OK
{
  "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" }
  ]
}
GET /v1/seasons/{year} SUN

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.

PARAMTYPEDESCRIPTION
yearintegerMoon year, in the path.
REQUEST
curl https://api.moon369.org/v1/seasons/1928
RESPONSE200 OK
{
  "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" }
  ]
}
GET /v1/spec

Every constant of the standard, including the exact Moon second as a whole-number ratio. Build your own implementation from this alone.

REQUEST
curl https://api.moon369.org/v1/spec
RESPONSE200 OK
{
  "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"
}
04

ERRORS & LIMITS

Every error returns the same JSON shape with a stable code. Nanosecond values are strings, so no language loses precision.

STATUSCODEMEANING
400missing_param, bad_param, out_of_rangeInput missing, malformed or an impossible Moon date.
401invalid_keyThe key sent in Authorization is unknown.
404not_foundNo such route.
405method_not_allowedOnly GET (and OPTIONS for CORS).
429rate_limitedLimit reached. Wait for Retry-After seconds, use a key, or run the reference code locally.
ERROR RESPONSE400
{
  "error": {
    "code": "out_of_range",
    "message": "day must be 1 to 28 in moon 2"
  }
}
OPEN
No key

Limited per IP address: 120 requests a minute. Over that you get a 429 with Retry-After.

KEYED
Free key

Send Authorization: Bearer <key>. Limits are set per key. Responses carry X-Moon-Plan.

CACHING
Past is permanent

/now is never cached. Conversions, years and the spec are cached forever. CORS is open to every origin.

05

PRECISION

Moonmarks carry 9 decimal places: nanoseconds. Every event gets one exact, sortable moment on the Moon engine, with no time zone to misread.

FORMAT · YEAR.MOON.DAY HH:MM:SS.NNNNNNNNN
1928.05.03 08:57:39.035909351
CLOCK SOURCETYPICAL ACCURACYCLOCK VALUE
Phone or laptop, internet-synced (NTP)about 1 msdevice-ntp
Data center, precision time protocol (PTP)microsecondsserver-ptp
GPS-disciplined atomic referencetens of nanosecondsgps

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.

moon-precise.jsMIT
// 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"
06

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.jsMIT
// 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;
}
07

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.

ON DARK
Powered by Moon DOWNLOAD SVG
ON LIGHT
Powered by Moon DOWNLOAD SVG
EMBEDHTML
<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.
08

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.

DO
Say it runs on Moon

"Built on Moon time" or "Uses the Moon standard" in your copy is welcome.

DO
Use the official badge

Download the badge files as provided, in dark or light.

DON'T
Don't imply endorsement

No partnership, certification or "official" claims without written approval.

DON'T
Don't alter the mark

No recoloring, stretching, effects, or using the linked O's in your own logo.

DON'T
Don't name products Moon

Product, app and domain names can't use "Moon" as their brand.

DON'T
Don't fork the constants

If you change the epoch or the Moon second, it isn't Moon time. Don't call it that.

09

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.