Skip to main content

Moon Phase, Moonrise & Moonset API

REAL DATA

Moon phase, illumination, moonrise, moonset, lunar transit and topocentric position for any coordinate, plus every primary phase instant of a year. No key.

Authoritative reference data or standards computation

Base URL
/api/moon
Category
Date & Time
Capabilities
4 routes
Last updated
July 30, 2026
Data sources · 5
+2 more

GET /api/moon/phase

at is an absolute instant (a bare date means UTC midnight); omit it for now. Every value is geocentric — a topocentric observer's illuminated fraction differs by up to about 0.7 percentage points near the horizon, and that difference is not modelled.

Live requestRuns against the public API
No key required
GET/api/moon/phase?tz=Europe%2FCopenhagen

Request parameters

Absolute instant: YYYY-MM-DD (UTC midnight) or RFC 3339 with Z or an explicit offset, resolved year 1900–2100. Defaults to now.

IANA zone used to render `localTime` and every `local` inside the phase objects, case-insensitive. It never moves the instant; unknown ids return a 400.

Advanced response options4 options

Return only these fields (comma-separated). Mutually exclusive with 'exclude'.

Return all fields except these (comma-separated).

Pretty-print the JSON response.

Drop the envelope: return the raw array/object without data/meta wrapper.

Response

Example parameters are ready. Send the request to inspect the live response.

Route reference

Code samples Ready-to-copy requests in 4 languages
Choose a code sample language
curl "https://randomapi.dev/api/moon/phase?tz=Europe/Copenhagen"
const res = await fetch("https://randomapi.dev/api/moon/phase?tz=Europe/Copenhagen");
const { data, meta } = await res.json();
import requests

data = requests.get("https://randomapi.dev/api/moon/phase?tz=Europe/Copenhagen").json()["data"]
$json = json_decode(file_get_contents(
  "https://randomapi.dev/api/moon/phase?tz=Europe/Copenhagen"
), true);
$data = $json["data"];
Parameters Route-specific request inputs 2
at date

Absolute instant: YYYY-MM-DD (UTC midnight) or RFC 3339 with Z or an explicit offset, resolved year 1900–2100. Defaults to now.

example: at=2026-07-29T14:36:00Z
tz string

IANA zone used to render `localTime` and every `local` inside the phase objects, case-insensitive. It never moves the instant; unknown ids return a 400.

default: UTC
example: tz=Europe/Copenhagen
Universal parameters Shared response and formatting options 4
fields list

Return only these fields (comma-separated). Mutually exclusive with 'exclude'.

example: fields=at,timezone
exclude list

Return all fields except these (comma-separated).

example: exclude=nextFullMoon
pretty boolean

Pretty-print the JSON response.

default: false
example: pretty=true
unwrap boolean

Drop the envelope: return the raw array/object without data/meta wrapper.

default: false
example: unwrap=true
Response schema Fields returned in each record 15
at string (ISO 8601 UTC)

The evaluated instant in UTC.

example: 2026-07-29T14:36:00.000Z

timezone string

Canonical IANA id used to render `localTime` and every `local` inside the phase objects. It never moves the instant.

example: Europe/Copenhagen

localTime string (YYYY-MM-DDTHH:mm:ss)

Naive local wall clock of `at` in `timezone`.

example: 2026-07-29T16:36:00

illuminatedFraction float (0 to 1)

Fraction of the Moon's apparent disk that is sunlit, 0 at new and 1 at full. Geocentric — a topocentric observer's value differs by up to about 0.7 percentage points near the horizon. It never quite reaches 0 or 1: rounded to the five decimals returned here, the primary instants of 2026-2030 span 0.99811 to 1 at full and 0 to 0.00192 at new.

example: 0.99967

phaseAngleDegrees float (0 to 180)

Sun–Moon–Earth phase angle, derived from the true geocentric Sun–Earth–Moon separation, which includes the Moon's ecliptic latitude. It reaches exactly 0° at full and 180° at new **only when the Moon is at a node — that is, at an eclipse**: measured over every primary instant of 2026-2030 the full moons span 0.01°-4.99° and the new moons 174.98°-179.86°, so neither endpoint is ever actually attained.

example: 2.073

elongationDegrees float (0 to 360)

Geocentric elongation of the Moon east of the Sun in apparent ecliptic longitude: 0° new, 90° first quarter, 180° full, 270° last quarter. This is the quantity `phaseName`, `waxing` and the primary-phase root solve are all derived from.

example: 180.0031

phaseName string

Conventional name for `elongationDegrees`: `new`, `waxing-crescent`, `first-quarter`, `waxing-gibbous`, `full`, `waning-gibbous`, `last-quarter` or `waning-crescent`. **The sector boundaries are this API's documented convention, not a standard** — eight 45°-wide sectors centred on the four primary instants (`new` is 337.5°–360° and 0°–22.5°, `waxing-crescent` 22.5°–67.5°, and so on). Other publishers bin differently, so near a boundary a name can disagree with theirs; `nextPrimaryPhase` and /api/moon/phases carry the exact instants.

example: full

waxing boolean

True while `elongationDegrees` is in [0, 180) — the illuminated fraction is growing. Exactly 180.0 is reported as false (waning).

example: false

ageDays float

Days elapsed since `previousNewMoon.instant`. Ranges 0 to about 29.83, and is exactly 0 at a published new-moon instant.

example: 15.20313

lunationNumber integer

Brown Lunation Number of the cycle `at` falls in — lunation 1 is the cycle that began at the new moon of 1923 January 17 (02:41 UT). Always equal to the lunation of `previousNewMoon`.

example: 1281

distanceKm float

Geometric geocentric centre-to-centre distance in km. Sampled hourly over 2026-2036 it ranges 356 445.9 to 406 670.5.

example: 399616.1

apparentDiameterDegrees float

Geocentric apparent angular diameter of the lunar disk, from the IAU mean lunar radius applied to the horizontal parallax. Measured over 2026-2036 it ranges 0.4896° to 0.5585°.

example: 0.4982

previousNewMoon object

The new-moon instant that starts this lunation. Object with `instant` (UTC ISO 8601, whole seconds), `local` (naive wall clock in `tz`) and `deltaTSeconds`, the TT−UT offset applied to convert the Terrestrial-Time solve to UTC, so the conversion is auditable.

example: {"instant":"2026-07-14T09:43:30.000Z","local":"2026-07-14T11:43:30","deltaTSeconds":75.4}

nextPrimaryPhase object

The next of the four primary phases strictly after `at`, with `phase` naming which one (`new`, `first-quarter`, `full` or `last-quarter`). Object with `instant` (UTC ISO 8601, whole seconds), `local` (naive wall clock in `tz`) and `deltaTSeconds`, the TT−UT offset applied to convert the Terrestrial-Time solve to UTC, so the conversion is auditable.

example: {"phase":"last-quarter","instant":"2026-08-06T02:21:22.000Z","local":"2026-08-06T04:21:22","deltaTSeconds":75.5}

nextFullMoon object

The next full-moon instant strictly after `at`; at a published full-moon instant this is the following month's. Object with `instant` (UTC ISO 8601, whole seconds), `local` (naive wall clock in `tz`) and `deltaTSeconds`, the TT−UT offset applied to convert the Terrestrial-Time solve to UTC, so the conversion is auditable.

example: {"instant":"2026-08-28T04:18:25.000Z","local":"2026-08-28T06:18:25","deltaTSeconds":75.5}

Documented examples

Build-generated requests and complete responses
3
The Moon right now in Copenhagen
GET /api/moon/phase?tz=Europe/Copenhagen
{
  "data": {
    "at": "2026-07-30T15:14:08.000Z",
    "timezone": "Europe/Copenhagen",
    "localTime": "2026-07-30T17:14:08",
    "illuminatedFraction": 0.98972,
    "phaseAngleDegrees": 11.6412,
    "elongationDegrees": 191.631,
    "phaseName": "full",
    "waxing": false,
    "ageDays": 16.22961,
    "lunationNumber": 1281,
    "distanceKm": 396703.3,
    "apparentDiameterDegrees": 0.5019,
    "previousNewMoon": {
      "instant": "2026-07-14T09:43:30.000Z",
      "local": "2026-07-14T11:43:30",
      "deltaTSeconds": 75.4
    },
    "nextPrimaryPhase": {
      "phase": "last-quarter",
      "instant": "2026-08-06T02:21:22.000Z",
      "local": "2026-08-06T04:21:22",
      "deltaTSeconds": 75.5
    },
    "nextFullMoon": {
      "instant": "2026-08-28T04:18:25.000Z",
      "local": "2026-08-28T06:18:25",
      "deltaTSeconds": 75.5
    }
  },
  "meta": {
    "endpoint": "moon",
    "route": "/phase",
    "params": {
      "tz": "Europe/Copenhagen",
      "at": "2026-07-30T15:14:08.000Z"
    },
    "generatedAt": "2026-07-30T15:14:08.000Z"
  }
}
The July 2026 full moon instant
GET /api/moon/phase?at=2026-07-29T14:36:00Z
{
  "data": {
    "at": "2026-07-29T14:36:00.000Z",
    "timezone": "UTC",
    "localTime": "2026-07-29T14:36:00",
    "illuminatedFraction": 0.99967,
    "phaseAngleDegrees": 2.073,
    "elongationDegrees": 180.0031,
    "phaseName": "full",
    "waxing": false,
    "ageDays": 15.20313,
    "lunationNumber": 1281,
    "distanceKm": 399616.1,
    "apparentDiameterDegrees": 0.4982,
    "previousNewMoon": {
      "instant": "2026-07-14T09:43:30.000Z",
      "local": "2026-07-14T09:43:30",
      "deltaTSeconds": 75.4
    },
    "nextPrimaryPhase": {
      "phase": "last-quarter",
      "instant": "2026-08-06T02:21:22.000Z",
      "local": "2026-08-06T02:21:22",
      "deltaTSeconds": 75.5
    },
    "nextFullMoon": {
      "instant": "2026-08-28T04:18:25.000Z",
      "local": "2026-08-28T04:18:25",
      "deltaTSeconds": 75.5
    }
  },
  "meta": {
    "endpoint": "moon",
    "route": "/phase",
    "params": {
      "at": "2026-07-29T14:36:00.000Z",
      "tz": "UTC"
    },
    "generatedAt": "2026-07-30T15:14:08.000Z"
  }
}
The Moon on 1992 April 12
GET /api/moon/phase?at=1992-04-12T00:00:00Z
{
  "data": {
    "at": "1992-04-12T00:00:00.000Z",
    "timezone": "UTC",
    "localTime": "1992-04-12T00:00:00",
    "illuminatedFraction": 0.67864,
    "phaseAngleDegrees": 69.0671,
    "elongationDegrees": 110.8361,
    "phaseName": "first-quarter",
    "waxing": true,
    "ageDays": 8.79066,
    "lunationNumber": 857,
    "distanceKm": 368404.9,
    "apparentDiameterDegrees": 0.5404,
    "previousNewMoon": {
      "instant": "1992-04-03T05:01:27.000Z",
      "local": "1992-04-03T05:01:27",
      "deltaTSeconds": 58.6
    },
    "nextPrimaryPhase": {
      "phase": "full",
      "instant": "1992-04-17T04:42:28.000Z",
      "local": "1992-04-17T04:42:28",
      "deltaTSeconds": 58.6
    },
    "nextFullMoon": {
      "instant": "1992-04-17T04:42:28.000Z",
      "local": "1992-04-17T04:42:28",
      "deltaTSeconds": 58.6
    }
  },
  "meta": {
    "endpoint": "moon",
    "route": "/phase",
    "params": {
      "at": "1992-04-12",
      "tz": "UTC"
    },
    "generatedAt": "2026-07-30T15:14:08.000Z"
  }
}

GET /api/moon/times

date is a local civil date in tz; omit it for today in that zone. The route reports the events that actually fall inside that local date — it does not pair a rise with a set. Because the lunar day is about 24 h 50 min long, a civil date can contain a moonset with no moonrise (or the reverse), and moonset can precede moonrise.

Live requestRuns against the public API
No key required
GET/api/moon/times?lat=55.6761&lng=12.5683&date=2026-07-29&tz=Europe%2FCopenhagen

Request parameters

Observer latitude in WGS 84 decimal degrees, positive north (−90 to 90).

Observer longitude in WGS 84 decimal degrees, positive east (−180 to 180).

Local civil date (YYYY-MM-DD) in the resolved zone, years 1900–2100. Defaults to today in that zone. An RFC 3339 timestamp is accepted too and is reduced to the local civil date that instant falls on in `tz` — except at exactly 00:00 UTC, which is indistinguishable from the bare date and is read as that calendar date.

IANA zone used to resolve the local civil date, its start and end instants, and every `local` wall clock, case-insensitive. Unknown ids return a 400 — browse them at /api/timezones.

Advanced response options4 options

Return only these fields (comma-separated). Mutually exclusive with 'exclude'.

Return all fields except these (comma-separated).

Pretty-print the JSON response.

Drop the envelope: return the raw array/object without data/meta wrapper.

Response

Example parameters are ready. Send the request to inspect the live response.

Route reference

Code samples Ready-to-copy requests in 4 languages
Choose a code sample language
curl "https://randomapi.dev/api/moon/times?lat=55.6761&lng=12.5683&date=2026-07-29&tz=Europe/Copenhagen"
const res = await fetch("https://randomapi.dev/api/moon/times?lat=55.6761&lng=12.5683&date=2026-07-29&tz=Europe/Copenhagen");
const { data, meta } = await res.json();
import requests

data = requests.get("https://randomapi.dev/api/moon/times?lat=55.6761&lng=12.5683&date=2026-07-29&tz=Europe/Copenhagen").json()["data"]
$json = json_decode(file_get_contents(
  "https://randomapi.dev/api/moon/times?lat=55.6761&lng=12.5683&date=2026-07-29&tz=Europe/Copenhagen"
), true);
$data = $json["data"];
Parameters Route-specific request inputs 4
lat float required

Observer latitude in WGS 84 decimal degrees, positive north (−90 to 90).

allowed: -90 – 90
example: lat=55.6761
lng float required

Observer longitude in WGS 84 decimal degrees, positive east (−180 to 180).

allowed: -180 – 180
example: lng=12.5683
date date

Local civil date (YYYY-MM-DD) in the resolved zone, years 1900–2100. Defaults to today in that zone. An RFC 3339 timestamp is accepted too and is reduced to the local civil date that instant falls on in `tz` — except at exactly 00:00 UTC, which is indistinguishable from the bare date and is read as that calendar date.

example: date=2026-07-29
tz string

IANA zone used to resolve the local civil date, its start and end instants, and every `local` wall clock, case-insensitive. Unknown ids return a 400 — browse them at /api/timezones.

default: UTC
example: tz=Europe/Copenhagen
Universal parameters Shared response and formatting options 4
fields list

Return only these fields (comma-separated). Mutually exclusive with 'exclude'.

example: fields=date,timezone
exclude list

Return all fields except these (comma-separated).

example: exclude=extraEvents
pretty boolean

Pretty-print the JSON response.

default: false
example: pretty=true
unwrap boolean

Drop the envelope: return the raw array/object without data/meta wrapper.

default: false
example: unwrap=true
Response schema Fields returned in each record 10
date string (YYYY-MM-DD)

The local civil date the results describe, in the resolved zone.

example: 2026-07-29

timezone string

Canonical IANA id used to resolve the local date, its start and end instants, and every `local` wall clock.

example: Europe/Copenhagen

latitude float

Observer latitude in decimal degrees, echoed as supplied.

example: 55.6761

longitude float

Observer longitude in decimal degrees, echoed as supplied.

example: 12.5683

moonrise object

First moonrise inside the local date — the Moon's upper limb apparently touching the horizon. Object with `instant` (UTC ISO 8601, whole seconds), `local` (naive wall clock in `tz`), `azimuthDegrees` (compass bearing at the crossing, 0° = north increasing clockwise) and `reason`. On an ordinary date `reason` is null; when the event does not happen all three others are null and `reason` is `crossing-falls-on-another-date`, `above-horizon-all-day` or `below-horizon-all-day`. No placeholder time is ever substituted.

example: {"instant":"2026-07-29T19:35:56.000Z","local":"2026-07-29T21:35:56","azimuthDegrees":127.07,"reason":null}

moonset object

First moonset inside the local date. **May be earlier than `moonrise`**: on the example date the Moon set at 04:23 local and rose again at 21:35. Object with `instant` (UTC ISO 8601, whole seconds), `local` (naive wall clock in `tz`), `azimuthDegrees` (compass bearing at the crossing, 0° = north increasing clockwise) and `reason`. On an ordinary date `reason` is null; when the event does not happen all three others are null and `reason` is `crossing-falls-on-another-date`, `above-horizon-all-day` or `below-horizon-all-day`. No placeholder time is ever substituted.

example: {"instant":"2026-07-29T02:23:54.000Z","local":"2026-07-29T04:23:54","azimuthDegrees":226.84,"reason":null}

upperTransit object

First upper meridian transit inside the local date: `{ instant, local, altitudeDegrees, reason }`, where `altitudeDegrees` is the topocentric geometric altitude at culmination (no refraction). Its UTC date can be the previous day, and the altitude can be negative — this endpoint publishes a transit that culminates below the horizon, which the USNO omits. `reason` is `crossing-falls-on-another-date` when the transit lands on a neighbouring local date, and then all three other members are null.

example: {"instant":"2026-07-28T22:48:09.000Z","local":"2026-07-29T00:48:09","altitudeDegrees":10.3,"reason":null}

aboveHorizonSeconds integer (0-172800)

Seconds inside this local civil date during which the Moon's upper limb is above the horizon, summed over every above-horizon interval, and never more than the length of the local date itself. **The upper bound is not 86400**: a local date is 23 or 25 hours long on a daylight-saving change, some zones shift by 30 or 45 minutes, and a historical date-line or standard-offset jump can make one local date far longer than a day — sweeping every IANA zone over 1900-2100 finds 150 such dates in 44 zones, the longest being Pacific/Kwajalein 1969-09-30 at 47 hours (169 200 s), where at a high enough latitude the Moon stays up for all of it.

example: 24478

illuminatedFractionAtTransit float (0 to 1) nullable

Geocentric illuminated fraction at the instant of `upperTransit` — the observationally meaningful value for that night, and generally *not* the value at local noon that almanacs print for the date. `null` on a date with no upper transit. For any other anchor call /api/moon/phase with an explicit `at`.

example: 0.99533

extraEvents object[]

Any *additional* rise, set or upper transit on the same local date beyond the first of each kind, chronologically: `{ type, instant, local }` with `type` one of `moonrise`, `moonset`, `upper-transit`. Empty on almost every date: from about 63° of latitude upward the daily retardation can put two events of the same kind inside one local date, which over the whole of 2026 happens on 2 dates at 63°N and 5 at 72°N. This is where they appear instead of being dropped.

example: []

Documented examples

Build-generated requests and complete responses
4
Copenhagen on the July 2026 full moon
GET /api/moon/times?lat=55.6761&lng=12.5683&date=2026-07-29&tz=Europe/Copenhagen
{
  "data": {
    "date": "2026-07-29",
    "timezone": "Europe/Copenhagen",
    "latitude": 55.6761,
    "longitude": 12.5683,
    "moonrise": {
      "instant": "2026-07-29T19:35:56.000Z",
      "local": "2026-07-29T21:35:56",
      "azimuthDegrees": 127.07,
      "reason": null
    },
    "moonset": {
      "instant": "2026-07-29T02:23:54.000Z",
      "local": "2026-07-29T04:23:54",
      "azimuthDegrees": 226.84,
      "reason": null
    },
    "upperTransit": {
      "instant": "2026-07-28T22:48:09.000Z",
      "local": "2026-07-29T00:48:09",
      "altitudeDegrees": 10.3,
      "reason": null
    },
    "aboveHorizonSeconds": 24478,
    "illuminatedFractionAtTransit": 0.99533,
    "extraEvents": []
  },
  "meta": {
    "endpoint": "moon",
    "route": "/times",
    "params": {
      "lat": 55.6761,
      "lng": 12.5683,
      "date": "2026-07-29",
      "tz": "Europe/Copenhagen"
    },
    "generatedAt": "2026-07-30T15:14:08.000Z"
  }
}
The Copenhagen date with no moonrise
GET /api/moon/times?lat=55.6761&lng=12.5683&date=2026-08-08&tz=Europe/Copenhagen
{
  "data": {
    "date": "2026-08-08",
    "timezone": "Europe/Copenhagen",
    "latitude": 55.6761,
    "longitude": 12.5683,
    "moonrise": {
      "instant": null,
      "local": null,
      "azimuthDegrees": null,
      "reason": "crossing-falls-on-another-date"
    },
    "moonset": {
      "instant": "2026-08-08T16:42:15.000Z",
      "local": "2026-08-08T18:42:15",
      "azimuthDegrees": 326.02,
      "reason": null
    },
    "upperTransit": {
      "instant": "2026-08-08T06:54:14.000Z",
      "local": "2026-08-08T08:54:14",
      "altitudeDegrees": 61.48,
      "reason": null
    },
    "aboveHorizonSeconds": 67335,
    "illuminatedFractionAtTransit": 0.25871,
    "extraEvents": []
  },
  "meta": {
    "endpoint": "moon",
    "route": "/times",
    "params": {
      "lat": 55.6761,
      "lng": 12.5683,
      "date": "2026-08-08",
      "tz": "Europe/Copenhagen"
    },
    "generatedAt": "2026-07-30T15:14:08.000Z"
  }
}
Tromsø with the Moon below the horizon all day
GET /api/moon/times?lat=69.6492&lng=18.9553&date=2026-07-27&tz=Europe/Oslo
{
  "data": {
    "date": "2026-07-27",
    "timezone": "Europe/Oslo",
    "latitude": 69.6492,
    "longitude": 18.9553,
    "moonrise": {
      "instant": null,
      "local": null,
      "azimuthDegrees": null,
      "reason": "below-horizon-all-day"
    },
    "moonset": {
      "instant": null,
      "local": null,
      "azimuthDegrees": null,
      "reason": "below-horizon-all-day"
    },
    "upperTransit": {
      "instant": "2026-07-27T21:32:25.000Z",
      "local": "2026-07-27T23:32:25",
      "altitudeDegrees": -6.66,
      "reason": null
    },
    "aboveHorizonSeconds": 0,
    "illuminatedFractionAtTransit": 0.97181,
    "extraEvents": []
  },
  "meta": {
    "endpoint": "moon",
    "route": "/times",
    "params": {
      "lat": 69.6492,
      "lng": 18.9553,
      "date": "2026-07-27",
      "tz": "Europe/Oslo"
    },
    "generatedAt": "2026-07-30T15:14:08.000Z"
  }
}
Tonight in Sydney
GET /api/moon/times?lat=-33.8688&lng=151.2093&tz=Australia/Sydney
{
  "data": {
    "date": "2026-07-31",
    "timezone": "Australia/Sydney",
    "latitude": -33.8688,
    "longitude": 151.2093,
    "moonrise": {
      "instant": "2026-07-31T08:47:57.000Z",
      "local": "2026-07-31T18:47:57",
      "azimuthDegrees": 104.72,
      "reason": null
    },
    "moonset": {
      "instant": "2026-07-30T21:41:04.000Z",
      "local": "2026-07-31T07:41:04",
      "azimuthDegrees": 252.31,
      "reason": null
    },
    "upperTransit": {
      "instant": "2026-07-30T14:48:43.000Z",
      "local": "2026-07-31T00:48:43",
      "altitudeDegrees": 71.95,
      "reason": null
    },
    "aboveHorizonSeconds": 46387,
    "illuminatedFractionAtTransit": 0.99006,
    "extraEvents": []
  },
  "meta": {
    "endpoint": "moon",
    "route": "/times",
    "params": {
      "lat": -33.8688,
      "lng": 151.2093,
      "tz": "Australia/Sydney",
      "date": "2026-07-31"
    },
    "generatedAt": "2026-07-30T15:14:08.000Z"
  }
}

GET /api/moon/position

at is an absolute instant; omit it for now. Altitude is topocentric and geometric — parallax for the observer's position on the WGS 84 ellipsoid is applied, atmospheric refraction is not.

Live requestRuns against the public API
No key required
GET/api/moon/position?lat=55.6761&lng=12.5683&at=2026-07-29T00%3A00%3A00Z&tz=Europe%2FCopenhagen

Request parameters

Observer latitude in WGS 84 decimal degrees, positive north (−90 to 90).

Observer longitude in WGS 84 decimal degrees, positive east (−180 to 180).

Absolute instant: YYYY-MM-DD (UTC midnight) or RFC 3339 with Z or an explicit offset, resolved year 1900–2100. Defaults to now.

IANA zone used only to render `localTime`, case-insensitive. It does not move the instant; unknown ids return a 400.

Advanced response options4 options

Return only these fields (comma-separated). Mutually exclusive with 'exclude'.

Return all fields except these (comma-separated).

Pretty-print the JSON response.

Drop the envelope: return the raw array/object without data/meta wrapper.

Response

Example parameters are ready. Send the request to inspect the live response.

Route reference

Code samples Ready-to-copy requests in 4 languages
Choose a code sample language
curl "https://randomapi.dev/api/moon/position?lat=55.6761&lng=12.5683&at=2026-07-29T00:00:00Z&tz=Europe/Copenhagen"
const res = await fetch("https://randomapi.dev/api/moon/position?lat=55.6761&lng=12.5683&at=2026-07-29T00:00:00Z&tz=Europe/Copenhagen");
const { data, meta } = await res.json();
import requests

data = requests.get("https://randomapi.dev/api/moon/position?lat=55.6761&lng=12.5683&at=2026-07-29T00:00:00Z&tz=Europe/Copenhagen").json()["data"]
$json = json_decode(file_get_contents(
  "https://randomapi.dev/api/moon/position?lat=55.6761&lng=12.5683&at=2026-07-29T00:00:00Z&tz=Europe/Copenhagen"
), true);
$data = $json["data"];
Parameters Route-specific request inputs 4
lat float required

Observer latitude in WGS 84 decimal degrees, positive north (−90 to 90).

allowed: -90 – 90
example: lat=55.6761
lng float required

Observer longitude in WGS 84 decimal degrees, positive east (−180 to 180).

allowed: -180 – 180
example: lng=12.5683
at date

Absolute instant: YYYY-MM-DD (UTC midnight) or RFC 3339 with Z or an explicit offset, resolved year 1900–2100. Defaults to now.

example: at=2026-07-29T00:00:00Z
tz string

IANA zone used only to render `localTime`, case-insensitive. It does not move the instant; unknown ids return a 400.

default: UTC
example: tz=Europe/Copenhagen
Universal parameters Shared response and formatting options 4
fields list

Return only these fields (comma-separated). Mutually exclusive with 'exclude'.

example: fields=at,timezone
exclude list

Return all fields except these (comma-separated).

example: exclude=aboveHorizon
pretty boolean

Pretty-print the JSON response.

default: false
example: pretty=true
unwrap boolean

Drop the envelope: return the raw array/object without data/meta wrapper.

default: false
example: unwrap=true
Response schema Fields returned in each record 15
at string (ISO 8601 UTC)

The evaluated instant in UTC.

example: 2026-07-29T00:00:00.000Z

timezone string

Canonical IANA id used to render `localTime`. It does not move the instant.

example: Europe/Copenhagen

localTime string (YYYY-MM-DDTHH:mm:ss)

Naive local wall clock of the same instant.

example: 2026-07-29T02:00:00

latitude float

Observer latitude, echoed as supplied.

example: 55.6761

longitude float

Observer longitude, echoed as supplied.

example: 12.5683

altitudeDegrees float (-90 to 90)

Topocentric geometric altitude of the Moon's centre above the true horizon. No refraction correction, so near the horizon the apparent Moon sits roughly 0.57° higher. Observer elevation is taken as sea level.

example: 9.0873

azimuthDegrees float (0 to 360)

Compass bearing, 0° = north increasing clockwise. Within a hair of the zenith or of a pole the bearing is geometrically undefined and the meridian convention is reported instead: 180 for an observer north of the equator, 0 otherwise — the same convention /api/sun uses.

example: 196.2188

rightAscensionDegrees float (0 to 360)

Apparent topocentric right ascension, referred to the **true equator and equinox of date**. Not the ICRF/J2000 value — comparing it against an astrometric ICRF ephemeris shows the accumulated precession, not an error.

example: 301.6825

declinationDegrees float (-90 to 90)

Apparent topocentric declination, true equator of date.

example: -23.8409

distanceKm float

Topocentric centre-to-centre distance in km — up to about 6 400 km shorter than the geocentric distance /api/moon/phase reports, because the observer is off the Earth's centre.

example: 400076.5

horizontalParallaxDegrees float

Geocentric horizontal parallax of the Moon — `asin(6378.137 km / distance)` on the WGS 84 equatorial radius. Measured over 2026-2036 it ranges 0.8987° to 1.0253°.

example: 0.911

apparentDiameterDegrees float

Topocentric apparent angular diameter of the lunar disk.

example: 0.4976

parallacticAngleDegrees float (-180 to 180)

Angle at the Moon between the direction to the celestial north pole and the direction to the zenith. Implementations disagree on the sign, so the convention here is stated operationally: `atan2(cos φ · sin H, sin φ · cos δ − cos φ · sin δ · cos H)` with H the local hour angle — 0 at upper transit for an object south of the zenith, positive after transit (object west of the meridian), and ±180 near lower transit.

example: 9.9148

hourAngleDegrees float (-180 to 180)

Local apparent hour angle of the Moon: 0 at upper transit, negative before it, positive after. It advances at about 14.49° per hour, not 15° — the Moon's own eastward motion is subtracted.

example: 17.5494

aboveHorizon boolean

True when the Moon's upper limb is above the horizon by the *same* definition /api/moon/times uses for moonrise and moonset, so the two routes always agree.

example: true

Documented examples

Build-generated requests and complete responses
3
The Moon over Copenhagen at 00:00 UTC
GET /api/moon/position?lat=55.6761&lng=12.5683&at=2026-07-29T00:00:00Z&tz=Europe/Copenhagen
{
  "data": {
    "at": "2026-07-29T00:00:00.000Z",
    "timezone": "Europe/Copenhagen",
    "localTime": "2026-07-29T02:00:00",
    "latitude": 55.6761,
    "longitude": 12.5683,
    "altitudeDegrees": 9.0873,
    "azimuthDegrees": 196.2188,
    "rightAscensionDegrees": 301.6825,
    "declinationDegrees": -23.8409,
    "distanceKm": 400076.5,
    "horizontalParallaxDegrees": 0.911,
    "apparentDiameterDegrees": 0.4976,
    "parallacticAngleDegrees": 9.9148,
    "hourAngleDegrees": 17.5494,
    "aboveHorizon": true
  },
  "meta": {
    "endpoint": "moon",
    "route": "/position",
    "params": {
      "lat": 55.6761,
      "lng": 12.5683,
      "at": "2026-07-29",
      "tz": "Europe/Copenhagen"
    },
    "generatedAt": "2026-07-30T15:14:08.000Z"
  }
}
The Moon over Tromsø just before midnight
GET /api/moon/position?lat=69.6492&lng=18.9553&at=2026-07-29T21:56:00Z&tz=Europe/Oslo
{
  "data": {
    "at": "2026-07-29T21:56:00.000Z",
    "timezone": "Europe/Oslo",
    "localTime": "2026-07-29T23:56:00",
    "latitude": 69.6492,
    "longitude": 18.9553,
    "altitudeDegrees": -0.8195,
    "azimuthDegrees": 163.3569,
    "rightAscensionDegrees": 313.296,
    "declinationDegrees": -20.2779,
    "distanceKm": 398815.1,
    "horizontalParallaxDegrees": 0.9164,
    "apparentDiameterDegrees": 0.4992,
    "parallacticAngleDegrees": -6.0954,
    "hourAngleDegrees": -17.7763,
    "aboveHorizon": false
  },
  "meta": {
    "endpoint": "moon",
    "route": "/position",
    "params": {
      "lat": 69.6492,
      "lng": 18.9553,
      "at": "2026-07-29T21:56:00.000Z",
      "tz": "Europe/Oslo"
    },
    "generatedAt": "2026-07-30T15:14:08.000Z"
  }
}
The Moon right now over Sydney
GET /api/moon/position?lat=-33.8688&lng=151.2093&tz=Australia/Sydney
{
  "data": {
    "at": "2026-07-30T15:14:08.000Z",
    "timezone": "Australia/Sydney",
    "localTime": "2026-07-31T01:14:08",
    "latitude": -33.8688,
    "longitude": 151.2093,
    "altitudeDegrees": 71.0101,
    "azimuthDegrees": 341.2164,
    "rightAscensionDegrees": 321.7682,
    "declinationDegrees": -15.7337,
    "distanceKm": 390667.1,
    "horizontalParallaxDegrees": 0.9212,
    "apparentDiameterDegrees": 0.5096,
    "parallacticAngleDegrees": 163.8732,
    "hourAngleDegrees": 6.2494,
    "aboveHorizon": true
  },
  "meta": {
    "endpoint": "moon",
    "route": "/position",
    "params": {
      "lat": -33.8688,
      "lng": 151.2093,
      "tz": "Australia/Sydney",
      "at": "2026-07-30T15:14:08.000Z"
    },
    "generatedAt": "2026-07-30T15:14:08.000Z"
  }
}

GET /api/moon/phases

year selects by the local civil year in tz, so tz genuinely changes which instants are in scope near 1 January. Omit year for the current year in that zone. count acts as a limit only — a year holds 49 or 50 primary phases.

Live requestRuns against the public API
No key required
GET/api/moon/phases?year=2026

Request parameters

Local civil year in the resolved zone (1900–2100). Defaults to the current year in that zone.

Keep only one of the four primary phases, matched case-insensitively. Omit for all four.

IANA zone that selects the civil year and renders every `local` wall clock, case-insensitive. Unknown ids return a 400.

Advanced response options6 options

Limit the number of returned records (1–100). Defaults to all matches.

Return only these fields (comma-separated). Mutually exclusive with 'exclude'.

Return all fields except these (comma-separated).

Response format: json envelope, ndjson (one record per line) or csv.

Pretty-print the JSON response.

Drop the envelope: return the raw array/object without data/meta wrapper.

Response

Example parameters are ready. Send the request to inspect the live response.

Route reference

Code samples Ready-to-copy requests in 4 languages
Choose a code sample language
curl "https://randomapi.dev/api/moon/phases?year=2026"
const res = await fetch("https://randomapi.dev/api/moon/phases?year=2026");
const { data, meta } = await res.json();
import requests

data = requests.get("https://randomapi.dev/api/moon/phases?year=2026").json()["data"]
$json = json_decode(file_get_contents(
  "https://randomapi.dev/api/moon/phases?year=2026"
), true);
$data = $json["data"];
Parameters Route-specific request inputs 3
year int

Local civil year in the resolved zone (1900–2100). Defaults to the current year in that zone.

allowed: 1900 – 2100
example: year=2026
phase enum

Keep only one of the four primary phases, matched case-insensitively. Omit for all four.

allowed: new | first-quarter | full | last-quarter
example: phase=full
tz string

IANA zone that selects the civil year and renders every `local` wall clock, case-insensitive. Unknown ids return a 400.

default: UTC
example: tz=Europe/Copenhagen
Universal parameters Shared response and formatting options 6
count int

Limit the number of returned records (1–100). Defaults to all matches.

default: all matches
allowed: 1 – 100
example: count=3
fields list

Return only these fields (comma-separated). Mutually exclusive with 'exclude'.

example: fields=phase,instant
exclude list

Return all fields except these (comma-separated).

example: exclude=deltaTSeconds
format enum

Response format: json envelope, ndjson (one record per line) or csv.

default: json
allowed: json | ndjson | csv
example: format=csv
pretty boolean

Pretty-print the JSON response.

default: false
example: pretty=true
unwrap boolean

Drop the envelope: return the raw array/object without data/meta wrapper.

default: false
example: unwrap=true
Response schema Fields returned in each record 6
phase string

One of `new`, `first-quarter`, `full` or `last-quarter`.

example: full

instant string (ISO 8601 UTC)

The exact instant of the phase in UTC, rounded to the second.

example: 2026-07-29T14:35:36.000Z

local string (YYYY-MM-DDTHH:mm:ss)

Naive local wall clock of the same instant in `tz`.

example: 2026-07-29T16:35:36

localDate string (YYYY-MM-DD)

The local civil date in `tz` the instant falls on — the value `year` filters against.

example: 2026-07-29

lunationNumber integer

Brown Lunation Number of the cycle this phase belongs to (lunation 1 began at the new moon of 1923 January 17). All four phases of one cycle share it.

example: 1281

deltaTSeconds float

The TT−UT offset applied to convert the Terrestrial-Time solve to UTC, so the conversion is auditable.

example: 75.4

Documented examples

Build-generated requests and complete responses
3
Every primary phase of 2026 in UTC
GET /api/moon/phases?year=2026
{
  "data": [
    {
      "phase": "full",
      "instant": "2026-01-03T10:02:49.000Z",
      "local": "2026-01-03T10:02:49",
      "localDate": "2026-01-03",
      "lunationNumber": 1274,
      "deltaTSeconds": 75.1
    },
    {
      "phase": "last-quarter",
      "instant": "2026-01-10T15:48:18.000Z",
      "local": "2026-01-10T15:48:18",
      "localDate": "2026-01-10",
      "lunationNumber": 1274,
      "deltaTSeconds": 75.1
    },
    {
      "phase": "new",
      "instant": "2026-01-18T19:51:53.000Z",
      "local": "2026-01-18T19:51:53",
      "localDate": "2026-01-18",
      "lunationNumber": 1275,
      "deltaTSeconds": 75.1
    },
    {
      "phase": "first-quarter",
      "instant": "2026-01-26T04:47:17.000Z",
      "local": "2026-01-26T04:47:17",
      "localDate": "2026-01-26",
      "lunationNumber": 1275,
      "deltaTSeconds": 75.1
    },
    {
      "phase": "full",
      "instant": "2026-02-01T22:09:09.000Z",
      "local": "2026-02-01T22:09:09",
      "localDate": "2026-02-01",
      "lunationNumber": 1275,
    …
    "generatedAt": "2026-07-30T15:14:08.000Z"
  }
}
Full moons of 2026 on the Copenhagen clock
GET /api/moon/phases?year=2026&phase=full&tz=Europe/Copenhagen
{
  "data": [
    {
      "phase": "full",
      "instant": "2026-01-03T10:02:49.000Z",
      "local": "2026-01-03T11:02:49",
      "localDate": "2026-01-03",
      "lunationNumber": 1274,
      "deltaTSeconds": 75.1
    },
    {
      "phase": "full",
      "instant": "2026-02-01T22:09:09.000Z",
      "local": "2026-02-01T23:09:09",
      "localDate": "2026-02-01",
      "lunationNumber": 1275,
      "deltaTSeconds": 75.2
    },
    {
      "phase": "full",
      "instant": "2026-03-03T11:37:47.000Z",
      "local": "2026-03-03T12:37:47",
      "localDate": "2026-03-03",
      "lunationNumber": 1276,
      "deltaTSeconds": 75.2
    },
    {
      "phase": "full",
      "instant": "2026-04-02T02:11:51.000Z",
      "local": "2026-04-02T04:11:51",
      "localDate": "2026-04-02",
      "lunationNumber": 1277,
      "deltaTSeconds": 75.3
    },
    {
      "phase": "full",
      "instant": "2026-05-01T17:23:04.000Z",
      "local": "2026-05-01T19:23:04",
      "localDate": "2026-05-01",
      "lunationNumber": 1278,
    …
    "generatedAt": "2026-07-30T15:14:08.000Z"
  }
}
This year's new moons
GET /api/moon/phases?phase=new
{
  "data": [
    {
      "phase": "new",
      "instant": "2026-01-18T19:51:53.000Z",
      "local": "2026-01-18T19:51:53",
      "localDate": "2026-01-18",
      "lunationNumber": 1275,
      "deltaTSeconds": 75.1
    },
    {
      "phase": "new",
      "instant": "2026-02-17T12:01:03.000Z",
      "local": "2026-02-17T12:01:03",
      "localDate": "2026-02-17",
      "lunationNumber": 1276,
      "deltaTSeconds": 75.2
    },
    {
      "phase": "new",
      "instant": "2026-03-19T01:23:23.000Z",
      "local": "2026-03-19T01:23:23",
      "localDate": "2026-03-19",
      "lunationNumber": 1277,
      "deltaTSeconds": 75.2
    },
    {
      "phase": "new",
      "instant": "2026-04-17T11:51:42.000Z",
      "local": "2026-04-17T11:51:42",
      "localDate": "2026-04-17",
      "lunationNumber": 1278,
      "deltaTSeconds": 75.3
    },
    {
      "phase": "new",
      "instant": "2026-05-16T20:00:56.000Z",
      "local": "2026-05-16T20:00:56",
      "localDate": "2026-05-16",
      "lunationNumber": 1279,
    …
    "generatedAt": "2026-07-30T15:14:08.000Z"
  }
}

About this API

Coverage & behavior

Lunar phase, rise and set times and topocentric position, evaluated per request from the ELP-2000/82B lunar solution (Chapront-Touzé & Chapront) and VSOP87D (Bretagnon & Francou) — both published openly by the Bureau des Longitudes and distributed as CDS catalogues — with the IAU 1980 nutation series and the Espenak & Meeus ΔT polynomials. There is no ephemeris file to download, no upstream service that can go down, and no key.

  • /api/moon/phase — illuminated fraction, phase angle, elongation, lunar age, distance, Brown lunation number and the surrounding primary-phase instants at one instant.
  • /api/moon/times — moonrise, moonset and lunar transit on one local civil date, with honest nulls when an event does not happen.
  • /api/moon/position — topocentric altitude, azimuth, apparent right ascension and declination, distance, parallax and parallactic angle at an instant.
  • /api/moon/phases — every new moon, first quarter, full moon and last quarter of a year, with the exact instant and the lunation number.

The Moon skips days, and this endpoint says so

Successive moonrises are about 24 h 50 min apart, so the lunar day drifts against the civil calendar: roughly once a month a local civil date contains a moonset but no moonrise at all (or the reverse), and moonset is often earlier than moonrise in the same record. Copenhagen on 2026-08-08 is a worked example — the Moon sets at 18:42 local, transits at 08:54, and never rises; moonrise.instant is null and moonrise.reason is crossing-falls-on-another-date. The next date, 2026-08-09, has a rise at 00:10. Nothing is invented to fill the gap, and the two events are never sorted or swapped into a plausible-looking pair.

At high latitude the Moon can also stay below the horizon for a whole date while being nearly fully lit — Tromsø on 2026-07-27 has neither a rise nor a set with the disk 95 % illuminated (reason: "below-horizon-all-day") — or produce two rises or two sets on one date, which the retardation makes possible from about 63° of latitude upward. Those extras go in extraEvents rather than being dropped — though they are genuinely rare: sweeping every date of 2026 finds them on 2 dates at 63°N, 4 at 66.5°N and 5 at 72°N, and on none at all at 60° or below.

/times reports the events that genuinely fall inside the requested local civil date, which is what every almanac does. The date's start and end instants are found by bisecting the zone's own calendar, never by adding 24 hours — so a 23-hour daylight-saving day, a 30- or 45-minute offset (Lord Howe, Kathmandu, Chatham) and the zones whose transition happens at 00:00 local, where local midnight is skipped or repeated outright (Santiago, Havana), all come out right. It also survives the historical date-line and standard-offset jumps that make a local civil date much longer than a day: sweeping every IANA zone across 1900–2100 finds 150 local dates longer than 25 hours in 44 zones — Pacific/Kwajalein 1969-09-30 is 47 hours long (it skipped a day at the date line), America/Inuvik 1952-12-31 is 32 hours, Antarctica/Macquarie 1919-03-31 is 34 hours — and each is served with the events and the above-horizon total of that actual window. That is why aboveHorizonSeconds is documented as 0–172800 rather than 0–86400, and why the value is clamped to the real window length rather than to a nominal day.

Accuracy — measured, not estimated

Every number below was measured, not assumed, by scripts/refresh-moon.mjs --online against two US-government services:

Compared against Scope Maximum difference
USNO published primary-phase instants 247 instants across 1900, 1950, 2000, 2026 and 2050 43 s
USNO published primary-phase instants, past 2050 99 instants across 2075 and 2099 108 s (ΔT prediction, not the series)
USNO published moonrise / moonset / transit 15 events, Copenhagen · Tromsø · New York · Sydney 25 s
USNO published illuminated percentage 7 dates, at local noon 0.47 pp (USNO prints whole percents)
JPL Horizons (DE441) geocentric apparent longitude, at fixed Terrestrial Time 110 007 epochs spanning 1900–2100, one every 16 hours 1.82″
JPL Horizons apparent ecliptic latitude same 0.88″
JPL Horizons geometric geocentric distance same 1.59 km
JPL Horizons illuminated percentage same 0.0026 pp
JPL Horizons topocentric apparent RA / Dec / azimuth / elevation, at fixed UTC 117 epochs, 1975 · 2026 · 2049 14.3″ / 5.2″ / 20.9″ / 9.9″

The count of primary phases in a year matched the USNO's exactly for every year tested. The fixed-Terrestrial-Time rows are a dense sweep of the whole window, not a hand-picked epoch list: an earlier revision of this page quoted a 14-epoch sample, whose maxima were 2–4× smaller and were not maxima at all.

The gap between the fixed-Terrestrial-Time figures (a couple of arcseconds) and the fixed-UTC ones (tens of arcseconds) is not the series: it is the disagreement between the Espenak & Meeus ΔT polynomials this endpoint uses and JPL's own ΔT. ΔT is observed in the past and predicted in the future, so the two models drift apart: about 7 s in 2026, 23 s in 2049 and 130 s by 2099. Phase instants therefore hold to well under a minute against the USNO through 2050 and widen to about two minutes near 2100 — the same caveat /api/sun/seasons carries. The ΔT actually applied is returned as deltaTSeconds on every phase object so the conversion is auditable.

The series, and what it leaves out

The shipped tables are a documented truncation of the published series: 314 + 168 + 162 ELP terms in longitude, latitude and distance (every term with an amplitude of at least 0.03″ or 0.06 km, from the Main Problem plus the Earth-figure and planetary perturbations), 130 + 23 VSOP87D terms for the Sun and 36 nutation terms. The tidal, Moon-figure, relativistic and solar-eccentricity perturbation families are dropped whole; measured over 1900–2100 they contribute at most 0.009″. Relative to the same series evaluated in full the truncation costs 0.911″ of longitude and 1.3999 km of distance. Not one coefficient is hand-typed: every upstream file is pinned by SHA-256 and re-parsed by scripts/refresh-moon.mjs --write, whose parser re-emits each record in the authors' own Fortran format and fails on the first row that does not round-trip.

Rise and set use the apparent contact of the Moon's upper limb with the horizon: topocentric geometric altitude of the centre at −(0.5667° + 0.2725·π), where π is the horizontal parallax at that instant, so the threshold swings between about −0.812° and −0.846° rather than being a constant. (That is algebraically the classical geocentric form 0.7275·π − 34′ with the parallax moved onto the position instead of the threshold; the constant geocentric value usually quoted is +0.125°.) /position's aboveHorizon uses the identical expression, so the two routes provably agree at every crossing. Crossings are found by scanning the local date's altitude every 10 minutes and refining each sign change to under half a second: over 10 minutes the Moon's altitude moves at most about 2.6°, so only a grazing extremum within a few hundredths of a degree of the threshold could hide a pair of crossings.

/api/moon/times publishes an upper transit even when the Moon culminates below the horizon, because the transit genuinely happens and its altitude is reported. The USNO omits those, so on a date like Tromsø 2026-07-29 this endpoint returns a transit where their table shows only a rise. That is a deliberate difference in what is published, not a difference in the numbers.

phaseName is this API's convention, not a standard: eight 45°-wide sectors of elongationDegrees centred on the four primary instants (new is 337.5°–360° and 0°–22.5°, waxing-crescent 22.5°–67.5°, and so on). Other publishers bin differently, so near a boundary a name can disagree with theirs — the USNO still says "Waxing Gibbous" where these sectors have already switched to full. nextPrimaryPhase and /api/moon/phases carry the exact instants, which is what to compare.

Deliberately not modelled

Eclipses (contact times need Besselian elements and node precision a truncated series does not deliver). Perigee and apogee instantsdistanceKm is returned, the instants are a separate series and are not claimed. "Supermoon", "blue moon", "harvest moon", "micromoon" — popular-media labels with no standards body behind them, left out for the same reason /api/sun leaves out golden hour. Lunar-calendar month starts, Hijri dates, Ramadan and Easter's lunar rule — an astronomical phase instant is not a calendrical month start, which depends on jurisdiction-specific crescent-visibility criteria or local sighting; that is exactly why /api/holidays still documents partial calendars, and this endpoint does not change it. Tides. Libration, position angle of the axis, selenographic coordinates and terminator geometry. Atmospheric refraction on /positionaltitudeDegrees is geometric, and only the fixed 34′ of mean refraction baked into the rise/set threshold is modelled. Observer elevation, the local horizon profile, pressure and temperature — sea level and standard conditions only. Astrology — no moon signs, houses or void-of-course. And UT1−UTC (under 0.9 s, unpredictable) is not modelled, so every instant is UTC treated as UT.

The illuminated fraction and phase angle are geocentric. Measured against JPL Horizons, a topocentric observer's illuminated fraction differs from the geocentric one by up to about 0.7 percentage points near the horizon, and that difference is not modelled.

These values are not suitable for navigational, legal or safety-critical use — use a national almanac office for that.

Every route is limited to years 1900–2100; anything outside returns a 400 rather than an unfitted extrapolation.

Use it for

  • Show tonight's moon phase and illumination in an app without bundling an ephemeris library
  • Schedule astrophotography or wildlife cameras around real moonrise, moonset and lunar transit at a site
  • Publish the next full moon date for a calendar, newsletter or events page
  • Plan dark-sky observing windows by combining lunar altitude with the Sun's twilight times
  • Backfill the moon phase for historical timestamps in a research or forensics dataset

Frequently asked questions

How do I get the moon phase and illumination from a free API?

Call /api/moon/phase?tz=Europe/Copenhagen. It returns illuminatedFraction, phaseAngleDegrees, elongationDegrees, phaseName and ageDays for the instant you ask about (now, if you omit at), plus the geocentric distance and the surrounding primary-phase instants. No key, no signup, no quota form.

Why does the API return null for moonrise on some days?

Because on roughly one date a month the Moon genuinely does not rise on that calendar date — successive moonrises are about 24 h 50 min apart, so the lunar day drifts against the civil one. Copenhagen on 2026-08-08 is a real example: the Moon sets at 18:42 local and transits at 08:54, and there is no moonrise at all, so moonrise.instant is null and moonrise.reason is crossing-falls-on-another-date. A placeholder time is never substituted.

How do I get the date of the next full moon?

/api/moon/phase returns nextFullMoon as an exact UTC instant plus the local wall clock in your tz. For a whole year at once, /api/moon/phases?year=2026&phase=full lists every full moon; drop phase to get all 49 or 50 primary phases of the year.

How accurate are the moonrise and moonset times?

Measured, not estimated: against the U.S. Naval Observatory's published times the worst difference over the reference set (Copenhagen, Tromsø, New York, Sydney) is 25 seconds, and primary-phase instants agree to within 43 seconds over 247 instants across 1900, 1950, 2000, 2026 and 2050. Against JPL Horizons at fixed Terrestrial Time, over 110 007 epochs spanning 1900–2100, one every 16 hours, the apparent lunar longitude holds to 1.82 arcseconds and the geocentric distance to 1.59 km. Accuracy widens to about two minutes near 2100 (108 s worst case over 99 instants across 2075 and 2099), where ΔT is a prediction rather than an observation, and grazing events, observer elevation, the local horizon profile and non-standard refraction are not modelled.

Does this API say when a lunar calendar month or Ramadan begins?

No. It computes astronomical phase instants; the start of a lunar or Hijri month depends on jurisdiction-specific crescent-visibility criteria or on local sighting, which is a different question. That is also why /api/holidays still documents partial calendars for some countries — this endpoint does not change that.

Standards & references