JSON API
Two endpoints, no key, no rate limit: the current model offset between lunar and Earth clocks, and the drift accumulated between any two dates.
What this is
Every number this API returns is a model value. No lunar time scale has been realized, and a coordinate time scale is not read by any real clock, so the API returns what the published rate figures predict — not a reading taken on the Moon. [1]Official The arithmetic is the same code that drives the clock on this site, and it is written out in full on the methodology page.
Because of that, every response carries three fields you cannot switch off: disclaimer,methodology and sources. If you show these numbers to someone else, show those fields too.
Endpoints
The version lives in the path, and the same version is repeated in the version field of every response. All responses are application/json; charset=utf-8, all times are UTC, and CORS is open: access-control-allow-origin: *, so a browser on any origin can call this directly.
| Endpoint | What it answers | Caching |
|---|---|---|
GET /api/v1/now | The model offset right now, for one or both rate figures. | public, max-age=1, s-maxage=1 |
GET /api/v1/drift | The drift accumulated between two moments you name. | public, max-age=3600 |
GET /api/v1/now
| Parameter | Accepted values | Default | What it changes | Source |
|---|---|---|---|---|
epoch | tcl-1977, j2000 | tcl-1977 | The moment the model starts counting from. J2000.0 is 12:00 TT, which is 2000-01-01T11:58:55.816Z in UTC — not noon UTC. | [1]Official |
rate | surface-vs-geoid, tcl-vs-tt, or a number greater than 0 and at most 1000 µs/day | both standard rates | Which pair of scales is compared: 56.02 µs/day is a lunar surface clock against an Earth geoid clock, 58.7 µs/day is TCL against TT. A number of your own comes back with no pair of scales attached, because you supplied it and we cannot name its referent. | [2] |
Example
Request:
curl https://lunartime.org/api/v1/nowResponse, shortened — the model array holds one entry per rate figure, andsources one entry per source those figures rest on:
{
"api": "lunartime.org",
"version": "v1",
"generated_utc": "2026-08-24T13:43:01.584Z",
"disclaimer": "Model values. No lunar time scale has been realized. See the methodology page.",
"methodology": "https://lunartime.org/clock/methodology/",
"utc": {
"iso": "2026-08-24T13:43:01.584Z",
"unix_ms": 1787578981584
},
"tt": {
"iso": "2026-08-24T13:44:10.768Z",
"offset_from_utc_s": 69.184
},
"model": [
{
"id": "surface-vs-geoid",
"label": "Lunar surface clock vs Earth geoid clock",
"faster": "clock near the Moon's selenoid",
"slower": "clock near Earth's geoid",
"rate_us_per_day": 56.02,
"epoch": "1977-01-01T00:00:00.000Z",
"elapsed_days": 18132.572,
"offset_us": 1015786.66,
"offset_s": 1.01578666,
"offset_formatted": "+1.015787 s",
"seconds_per_year": 0.0204613,
"years_per_second": 48.87,
"sources": [
"ashby-patla-2024",
"our-calculation-model"
]
}
],
"constants": {
"tai_minus_utc_s": 37,
"tt_minus_tai_s": 32.184,
"epoch_tcl_1977": "1977-01-01T00:00:00.000Z",
"epoch_j2000": "2000-01-01T11:58:55.816Z"
},
"sources": [
{
"id": "ashby-patla-2024",
"title": "A Relativistic Framework to Estimate Clock Rates on the Moon",
"issuer": "Neil Ashby and Bijunath R. Patla, NIST — The Astronomical Journal 168:112",
"url": "https://iopscience.iop.org/article/10.3847/1538-3881/ad643a",
"verified": "2026-08-23"
}
],
"license": "Free to use. Attribution requested: link to https://lunartime.org/"
}GET /api/v1/drift
Deterministic: the same input always gives the same answer, which is why this endpoint is cached for an hour. A to earlier than from is not an error — the result is negative and the sign is shown.
| Parameter | Accepted values | Default | What it changes | Source |
|---|---|---|---|---|
from | YYYY-MM-DD (midnight UTC) or a full ISO 8601 stamp ending in Z | required | Start of the interval. Outside 1900-01-01 … 2200-01-01 the request is refused: a constant-rate model is not credible that far out, and a plausible-looking number would be worse than a refusal. | [3] |
to | same as from | required | End of the interval; may be earlier than from. | [3] |
rate | surface-vs-geoid, tcl-vs-tt, or a number greater than 0 and at most 1000 µs/day | surface-vs-geoid | Which pair of scales the drift belongs to, exactly as on /now. | [4]Official |
Example
Request:
curl "https://lunartime.org/api/v1/drift?from=1977-01-01&to=2026-08-23"Response:
{
"api": "lunartime.org",
"version": "v1",
"input": {
"from": "1977-01-01T00:00:00.000Z",
"to": "2026-08-23T00:00:00.000Z",
"rate_us_per_day": 56.02,
"rate_id": "surface-vs-geoid"
},
"result": {
"days": 18131,
"microseconds": 1015698.62,
"seconds": 1.01569862,
"formatted": "+1.015699 s",
"years_per_second": 48.87
},
"pair": {
"faster": "clock near the Moon's selenoid",
"slower": "clock near Earth's geoid"
},
"disclaimer": "Model values. No lunar time scale has been realized. See the methodology page.",
"methodology": "https://lunartime.org/clock/methodology/",
"sources": [
"ashby-patla-2024",
"our-calculation-model"
],
"license": "Free to use. Attribution requested: link to https://lunartime.org/"
}Errors
Errors are JSON too, never an empty body and never HTML. The shape is always{"error":{"code":"…","parameter":"…","message":"…"}}, andparameter appears only when the error is about a parameter.
| Code | Status | When |
|---|---|---|
invalid_parameter | 400 | A required parameter is missing, or a value is not of the accepted shape. |
out_of_range | 400 | The value parses but lies outside the interval we are willing to model. |
not_found | 404 | No such endpoint in this version. |
method_not_allowed | 405 | Anything other than GET or OPTIONS. The response carriesallow: GET, OPTIONS; a preflight OPTIONS gets204. |
Using it
- Free, no key, no quota. Free to use. Attribution requested: link to https://lunartime.org/ If traffic from one caller starts to hurt the site we will limit it, and this page will say so before we do.
- Attribution. Where the number is shown, link to the page it came from — the
methodologyfield of every response is that link. - Say that it is a model. The
disclaimerfield is written to be displayed, not stripped. A microsecond figure without its pair of scales, or without the word model, misleads the reader in exactly the way this site exists to prevent.
Version policy
A breaking change gets a new path — /api/v2/ — and v1 keeps answering. Adding a field is not a breaking change, so parse responses leniently: ignore fields you do not know rather than failing on them. Removing or renaming a field, changing the meaning of one, or changing an error code is breaking, and will not happen inside a version.