API accuracy and residuals
Every JSON response from the CycleCalcs v2 API carries meta.accuracy.residuals_url, and it points here. All 28 shipped routes do it. This page is what that link owes you: a specific, checkable statement of what these numbers are worth, where the error actually comes from, and what is deliberately not computed at all.
Nothing on this page was copied from a specification. Every figure below was either read out of the shipped source or measured by invoking the shipped endpoints. Where a number varies, the measured range is given rather than a convenient single value.
On this page
The short answer
The claim the API makes on every single response, in meta.accuracy.statement, is this:
Positions are arcminute class for the Sun, Moon and planets across 1700 to 2200, degrading toward the ends of that window.
That is a claim about positions. For most callers the position is not what limits the answer. Three other things dominate, and in ordinary use they dominate by a wide margin. In descending order of size:
- The dip of the sea horizon is not modelled. If your observer is high up with a clear sea horizon, rise and set times are wrong by minutes, and in the opposite direction from the correction the API does apply. Measured: at 3000 m the published sunrise is 13.9 minutes later than a true sea horizon would give. Details, and the formula to apply it yourself.
- Refraction takes no weather. No temperature, pressure or humidity parameter is accepted anywhere in the API. A cold, high-pressure night moves a real sunrise by tens of seconds against what is published. Details and measured magnitudes.
- UT1 is treated as equal to UTC. No IERS bulletin is loaded, so any time that is really a question about how far the Earth has turned can be out by up to 0.9 s from that alone. Details.
The ephemeris itself is the smallest term in that list for almost every question this API is asked. That ordering is the useful thing to know, and it is why this page spends more words on horizons and clocks than on planetary theory.
The engine
There is one ephemeris and it is vendored into this repository: Astronomy Engine 2.1.19, MIT licensed, Copyright (c) 2019-2023 Don Cross. The vendored file is never edited, so its hash stays meaningful. Its SHA-256 is 068f1445ed0c636c94818fe6d20d7d125120e605e0bab9fc4675c3d531be5ad7, matched byte for byte against upstream v2.1.19 (412,025 bytes), and a build check recomputes that hash on every run and fails the build if it moves. The same record is published on the wire in meta.engine on every response and at /v2/attribution.
The models it carries, read from the vendored source rather than from anybody's summary:
| Quantity | Model in the vendored source |
|---|---|
| Planets | VSOP87 |
| Moon | The Nautical Almanac Office's Improved Lunar Ephemeris of 1954, deriving from E. W. Brown's lunar theory, adapted from Montenbruck and Pfleger |
| Pluto | A gravitational integration between 51 tabulated state vectors, not a series expansion |
| Nutation | IAU 2000B |
| Terrestrial Time | The Espenak and Meeus piecewise delta-T polynomial |
| Refraction | Saemundsson, as given by Meeus, in the engine's "normal" mode |
What the engine's own file documents about its accuracy: almost nothing, and it is honest to say so. The vendored source carries the MIT notice and no error table. The two accuracy-relevant sentences it does contain are worth quoting because they are the origin of two of the limits on this page. On its time class it says the library approximates UT1 and UTC as being the same thing, and that this gives sufficient accuracy for the precision requirements of that project. On its rise and set search it says it uses a correction of 34 arcminutes, and that real-world refraction varies with air temperature, pressure and humidity, which are outside the scope of the engine.
So the arcminute-class statement above is CycleCalcs's claim, not the engine's. Everything else on this page is a measurement of the shipped system, and where a claim could not be verified it is not made.
Source: netlify/lib/vendor/astronomy-engine.mjs and netlify/lib/vendor/engine-version.mjs, both in the repository.
Time scales: UT1 and delta-T
The instant you send is interpreted as UTC, or as local civil time in the zone you send in tz. From there:
UT1 is assumed equal to UTC
No IERS bulletin is loaded. Every response says so, in meta.time.ut1_source, and /v2/time repeats it inside the data as scales.ut1_note. The leap-second system keeps UT1 - UTC inside 0.9 s, so that is the bound.
In plain terms. A rise, set, transit or twilight time is a question about how far the Earth has turned. It is answered in UT1. Because UT1 is being read off a UTC clock, every one of those instants can be out by up to 0.9 s before any other error is counted. A millisecond in the output is a stable identifier, not a promise.
The 0.9 s bound is a property of the modern leap-second system, and the leap-second table this API carries begins in 1972. /v2/conventions states the consequence itself, under time_scales.ut1: for dates before about 1960 this is the dominant uncertainty in any rise or set time.
Delta-T, and the residual the response publishes
Terrestrial Time comes from the Espenak and Meeus model. TAI comes from the leap-second table, which starts in 1972; before that, /v2/time reports tai: null with tai_source: "undefined_before_1972" and a time_scale_undefined warning, rather than inventing a value.
Because TT - TAI is 32.184 s by definition, those two independent routes to the same instant can be differenced. That difference is the delta-T model's departure from the leap-second chain, and every /v2/time response publishes it as delta_t_model_residual_seconds. Measured:
| Instant (UTC) | delta_t (s) | TAI - UTC (s) | Residual (s) |
|---|---|---|---|
| 1972-01-01T12:00 | 42.211029 | 10 | 0.027 |
| 1980-01-01T12:00 | 50.478897 | 19 | -0.705 |
| 1990-01-01T12:00 | 56.870914 | 25 | -0.313 |
| 2000-01-01T12:00 | 63.847090 | 32 | -0.337 |
| 2010-01-01T12:00 | 66.684661 | 34 | 0.501 |
| 2020-01-01T12:00 | 71.578324 | 37 | 2.394 |
| 2026-07-31T12:00 | 75.407926 | 37 | 6.224 |
| 2040-01-01T12:00 | 84.720380 | 37 | 15.536 |
Read that table as follows. From 1972 to about 2010 the model tracks the real chain to well under a second, which is what you would want from a fit. After that it diverges, and it diverges in one direction. The Espenak and Meeus branch for years after 2005 is an extrapolating parabola, and the Earth's rotation did not follow it. Past the present day the residual is the model's error, and it grows.
What that means for you. Delta-T decides which ephemeris instant a given UTC is evaluated at. Measured effect of the present 6.22 s residual on geocentric apparent place: Moon 3.26 arcsec, Sun 0.25, Mercury 0.21, Mars 0.18, Jupiter 0.06. At the 2040 residual of 15.5 s: Moon 7.75 arcsec, Sun 0.66. Every one of those is far inside arcminute class, so for a position you can ignore it.
It matters when the question is about a point on the ground rather than a direction in the sky. The Earth turns about 0.465 km per second at the equator, so an error of a few seconds in delta-T carries a few kilometres straight into any answer of the form "where on the Earth". If that is your question, take delta_t_model_residual_seconds off the response and carry it through.
Refraction and the atmosphere
The model is Saemundsson, as given by Meeus and as implemented by the engine's Refraction() in normal mode. Not Bennett, which is a different expression with different coefficients. The exact evaluation, read from the vendored source:
// h is the GEOMETRIC altitude in degrees; result in arcminutes refraction = 1.02 / tan( (h + 10.3 / (h + 5.11)) degrees ) // h is clamped at -1.0 deg before evaluation, and below -1.0 deg // the result is tapered linearly to zero at the nadir
The three constants are 1.02, 10.3 and 5.11, and a build check re-reads them out of the vendored file on every run so this page and the code cannot drift apart. Values produced by the shipped code:
| Geometric altitude (deg) | Refraction (arcmin) |
|---|---|
| -1.0 | 38.795 |
| -0.8333 | 37.094 |
| -0.5667 | 34.359 |
| 0 | 28.982 |
| 1 | 21.744 |
| 5 | 9.674 |
| 10 | 5.408 |
| 30 | 1.746 |
| 60 | 0.585 |
There is no temperature or pressure in it
The Saemundsson expression as coded is a function of altitude alone. It embeds no temperature term and no pressure term, so there is nothing for a weather parameter to enter and nothing the refraction model can be said to "assume". This is why /v2/conventions publishes refraction.assumed_temperature_c and refraction.assumed_pressure_mbar as null.
The U.S. Standard Atmosphere (1976) does appear in this API, but somewhere else and doing something narrower. The engine's Atmosphere() gives relative air density at the observer's elevation, referenced to sea level at 15.0 C (288.15 K) and 1013.25 mbar (101325 Pa). The rise and set search uses it for one purpose only: to scale its fixed 34-arcminute horizon allowance by air density. Measured from the shipped code:
| Elevation (m) | Relative density | Pressure (mbar) | Temperature (C) | Scaled allowance (arcmin) |
|---|---|---|---|---|
| 0 | 1.00000 | 1013.25 | 15.00 | 34.000 |
| 500 | 0.95287 | 954.61 | 11.75 | 32.398 |
| 1000 | 0.90747 | 898.75 | 8.50 | 30.854 |
| 2000 | 0.82163 | 794.96 | 2.00 | 27.935 |
| 3000 | 0.74215 | 701.09 | -4.50 | 25.233 |
Those temperatures and pressures are the standard atmosphere's own profile, used to get a density ratio. They are not weather, and sending your own is not possible.
No weather parameter is accepted, anywhere
The 28 shipped routes advertise 68 distinct parameters between them. None of them is a temperature, a pressure or a humidity. (depressions and sun_depression_deg are solar depression angles for twilight, not atmospheric.) This is a deliberate limit, not an oversight: a refraction model with no weather term cannot use weather you supply, and accepting a parameter that changes nothing would be worse than refusing it.
The magnitude of what you are giving up. The classical scaling for non-standard conditions, from Meeus, multiplies refraction by (P / 1010) * (283 / (273 + T)) with P in millibars and T in degrees Celsius. This API does not apply it. Worked against the 34-arcminute horizon allowance:
| Conditions | Factor | Allowance (arcmin) | Change (arcmin) |
|---|---|---|---|
| -10 C, 1030 mbar (cold, high pressure) | 1.0974 | 37.31 | +3.31 |
| 0 C, 1020 mbar | 1.0469 | 35.59 | +1.59 |
| 15 C, 1013.25 mbar | 0.9858 | 33.52 | -0.48 |
| 30 C, 1000 mbar (hot, low pressure) | 0.9247 | 31.44 | -2.56 |
The cold case is 0.0552 deg of horizon. Run through the shipped search, that moves sunrise at London on 2026-06-21 28.2 s earlier than the published time. To convert any horizon error into a time error yourself, here is the sensitivity measured directly from the shipped search:
| Place and date | 0.0555 deg | 0.1667 deg | 0.5 deg |
|---|---|---|---|
| Equator, 2026-03-20 | 13.3 s | 40.0 s | 120.0 s |
| London (51.5 N), 2026-06-21 | 28.4 s | 85.4 s | 257.3 s |
| London (51.5 N), 2026-12-21 | 27.3 s | 81.8 s | 244.4 s |
| 60 N, 2026-06-01 | 42.2 s | 127.3 s | 385.8 s |
| 66 N, 2026-09-21 | 32.9 s | 98.8 s | 296.4 s |
So: ordinary weather is worth tens of seconds at mid-latitudes and more toward the poles. A strong low-level temperature inversion over cold ground can lift a body by far more than any of this, and no ephemeris in the world predicts that from a date and a coordinate.
Two things soften the blow. Every horizontal position in the API returns altitude_refracted_deg and altitude_unrefracted_deg side by side with refraction_deg between them, so you never have to guess which one you are holding and you can substitute your own model at will. And refraction=none is accepted on /v2/positions if you want the geometric altitude alone.
What a rise or set time solves for
This is the section most astronomy APIs do not write, and it is the one to read if you are comparing two services and finding a difference of a minute or two.
The engine's rise and set search targets horizon_dip - (34/60) * air_density and solves it against a geometric altitude: the horizon conversion inside the search is called with the refraction argument omitted, which the code reads as zero refraction. The crossing is therefore geometric, not refracted. It does apply the body's semidiameter, for the Sun and Moon only, and topocentric parallax for everything.
| Body | What the search solves | Geometric centre altitude at the event |
|---|---|---|
| Sun | Not the limb search. The API solves the Sun's centre at the classical 50 arcminutes below the true horizon: about 16 of semidiameter plus about 34 of refraction. | -0.8333 exactly, by adoption |
| Moon | Upper limb at the density-scaled 34-arcminute allowance. The centre therefore crosses at -0.5667 minus the Moon's own topocentric semidiameter, which is not a constant. | -0.8459 to -0.8116 measured, London, 2026 and 2027 |
| Every planet, and any fixed star you supply | The engine allows a point source no semidiameter, so the centre itself crosses the allowance. | -0.566904 to -0.566430 measured; the spread is the root finder's 0.1 s tolerance, not physics |
The Sun's value is a convention, not a computation. The Sun's real semidiameter runs from 15.73 to 16.27 arcminutes over a year, measured from the adopted solar radius of 696,000 km, so a fixed -0.8333 cannot be the limb at every date. It is the standard almanac definition and the API adopts it deliberately. The difference against the engine's own upper-limb search is small and is worth knowing: measured at London, the two differ by 2.10 s on 2026-01-03 and by 2.26 s on 2026-06-21, in opposite directions as the Earth-Sun distance crosses its mean.
The Moon's value genuinely has no single number. Its topocentric semidiameter at its own rise ranges from 14.69 to 16.75 arcminutes across the year, so quoting one figure for the Moon's crossing altitude would be wrong on most nights. That is why the API publishes the Moon's rise and set definition in words rather than a number, and why each event carries the altitude it actually solved for.
The rule to code against. If you need to answer "is this body up, the same way the rise and set search would answer it", compare the geometric centre altitude plus the body's angular radius against -0.5667 deg. Do not compare a refracted altitude against zero. For the Moon the two differ by about 0.2 deg, which is roughly two minutes of its motion, and mixing them is exactly how an observing tool reports a bright gibbous night as moonless.
The API states all of this on the wire rather than leaving you to infer it. A rise or set event reports the unrefracted altitude, because that is the value the search solved for. A transit reports the refracted altitude, because that is what an observer would measure. That rule is published once as event_altitude_convention at /v2/conventions, not repeated in every block, so a microcontroller does not pay for it on every request.
One coincidence worth knowing, because it is the reason the two conventions are not as far apart as they look. Saemundsson evaluated at the search target of -0.5667 deg gives 34.359 arcminutes, against the flat 34 the search uses. The gap is 0.36 arcminutes, about 3 s of time at London. The fixed allowance and the refraction model agree at the horizon and diverge above it, which is why refraction is not an accepted parameter on the rise and set path: there is no refraction model in that code path to switch off.
Elevation, and the horizon dip we do not model
Sending elevation_m raises the observer on a locally flat plateau. The dip of the sea horizon is not modelled: the engine's dip function is called with zero metres above ground, so it returns zero.
The only thing your elevation does to a rise or set time, therefore, is thin the air. Thinner air shrinks the 34-arcminute allowance, which raises the target altitude, which makes the event later. Measured through the shipped endpoints at London on 2026-06-21, UTC day anchor:
| Event | Sea level | 100 m | 1000 m | 3000 m |
|---|---|---|---|---|
| Moonrise | 11:39:57.7 | +2.2 s | +21.3 s | +59.5 s |
| Jupiter rise | 06:03:49.0 | +2.6 s | +24.9 s | +69.3 s |
| Sunrise | 03:42:45.401 | +0.000 s | +0.000 s | +0.001 s |
Sunrise does not move, to within a millisecond, because the Sun's target is the fixed -0.8333 deg and is not density-scaled. That inconsistency between the Sun and every other body is real, and it is stated here rather than smoothed over.
This is the largest routine error on this page, and the sign is the wrong way round. A real observer at 3000 m with a sea horizon sees the Sun about 13.9 minutes early, because the horizon has dropped 1.60 deg below their horizontal. The API instead reports sunrise unchanged, and reports moonrise and planet rises about a minute late. If your observer is on a mountain, a coastline cliff or an aircraft, you must apply the dip yourself.
The value you are forgoing is published by /v2/conventions precisely so that you can apply it: dip in arcminutes = 1.753 * sqrt(elevation in metres). Measured from the shipped helper:
| Elevation (m) | 10 | 100 | 1000 | 3000 |
|---|---|---|---|---|
| Dip (arcmin) | 5.54 | 17.53 | 55.43 | 96.02 |
Subtract the dip from the event altitude, re-solve, and use the sensitivity table in the refraction section if you only need the size of the shift. The dip is deliberately not applied by default because most callers at a nonzero elevation are inland, behind terrain, and would get a worse answer, not a better one.
The reliable date range
/v2 publishes Reliable from 1700 to 2200, and /v2/conventions publishes the same as date_range.min_year and date_range.max_year. Behaviour at the edges, verified by invoking the endpoints:
- Outside the range: a refusal, not a degraded answer. The year 1699 and the year 2205 both return
400 DATE_OUT_OF_RANGEwith the message naming the year and the supported range. - Within 20 years of either boundary:
/v2/positionsreturns200with anextrapolated_epochwarning. Verified at 1710 and at 2190. - The other date-taking endpoints do not emit that warning yet, and
/v2/conventionssays so indate_range.noterather than implying they do. Near a boundary, on those routes, the responsibility is yours.
The clearest single reason the window has ends is delta-T. From the shipped model:
| Year | 1700 | 1800 | 1900 | 2000 | 2026 | 2100 | 2200 |
|---|---|---|---|---|---|---|---|
| delta-T (s) | 8.9 | 13.6 | -2.2 | 64.0 | 75.3 | 203.7 | 443.1 |
Past 2150 the model is a bare parabola with no observational anchor whatever. The far end of the published range is an extrapolation, and the near-boundary warning exists to say so.
A separate fact, not a range boundary and deliberately reported differently: a time scale that did not exist at the requested instant comes back null with a time_scale_undefined warning. TAI before 1972 is the case you will meet.
Precision is not accuracy
Instants are printed to the millisecond. That is a stable identifier, not a claim, and this API would rather you know exactly how much of it is real.
| Quantity | Root finder tolerance |
|---|---|
| Rise, set and any altitude crossing (twilights, custom depressions) | 0.1 s |
| Moon phase instants | 0.1 s |
| Solar longitude crossings (equinoxes, solstices, cross-quarters) | 0.01 s |
Set those against the 0.9 s that UT1 alone is worth, and the tens of seconds that weather is worth near the horizon, and the ordering is clear: the search converges far tighter than the physics is known. The extra digits let you compare two responses and detect a change; they are not an error bar.
The precision parameter rounds decimals on output and changes nothing that was computed. Julian day fields are exempt from it by name, deliberately, because at precision=3 a Julian Day would round to the nearest 86 seconds and destroy the one field a caller reaches for when they want an instant to sub-second resolution.
Published disagreements
Where two defensible models of the same quantity exist, this API computes both, answers from the one it has chosen, and publishes the difference. A residual on the wire is more useful than a clean-looking number, because it tells you what you can and cannot ask of the answer.
The selenographic frame, on /v2/libration
The sub-Earth point comes from the engine's own libration function. The sub-solar point and the colongitude do not: the engine exposes no sub-solar function, so the Moon's body-fixed frame is rebuilt from its rotation axis using the IAU WGCCRE 2015 rotation elements. Two models, so the sub-Earth point is recomputed in the rebuilt frame and compared against the engine's own answer. The difference is published as method.cross_check_residual_deg.
| Sample | Residual (deg) |
|---|---|
| 2026-11-14T21:30Z, the reference instant | 0.020123 |
| 3653 daily samples, 2020 to 2029: minimum | 0.017496 |
| 3653 daily samples, 2020 to 2029: maximum | 0.027570 |
| 3653 daily samples, 2020 to 2029: mean | 0.022399 |
| Century marks 1700 / 1800 / 1900 / 2000 / 2100 / 2200 | 0.0229 / 0.0179 / 0.0197 / 0.0208 / 0.0240 / 0.0259 |
On a range request the published value is the worst residual across the rows, not an average, and a model_disagreement warning fires above 0.2 deg.
About 0.02 deg is roughly 0.6 km on the lunar surface at the sub-Earth point. It is stable across the whole supported date range, which is the signature of a frame that is built correctly rather than one that happens to agree today. The primary answer always comes from the engine's libration function: the recomputed angles are never averaged in, never preferred when they look better, and never silently substituted when the residual is large.
Publishing it costs nothing and buys two things. A caller who needs the colongitude to better than 0.6 km now knows they cannot have it here, instead of finding out later. And if that residual ever grew, the colongitude would be the first thing to distrust, so the number belongs on the wire rather than in a comment nobody reads.
Two supermoon rules, on /v2/phases
The same principle applied to a definition rather than to a frame. A full or new Moon is classified under the site's fixed distance rule and under Espenak's rule, which sets one threshold per calendar year at ten percent of the way from that year's closest perigee to its farthest apogee. When the two disagree the response says so and by how much. The full Moon of 2026-11-24 is a worked example: at 360,754 km it is 754 km outside the fixed 360,000 km line but 864 km inside the 2026 Espenak threshold of 361,618 km, so criteria_disagree is true and the response states in words that published lists following the two rules will disagree about this event.
Light time and the other corrections
/v2/conventions publishes the correction register as data. Applied: aberration and light travel time on every apparent place; nutation in every of-date frame; topocentric parallax whenever a latitude and longitude are supplied. Not applied: proper motion, and polar motion, which is milliarcsecond class and an explicit non-goal.
Topocentric parallax is worth stating in size because for the Moon it is enormous by the standards of everything else on this page. Measured at London through a full day, the largest geocentric-to-topocentric shift was 0.9279 deg, close to two lunar diameters.
Galilean events are evaluated at the light departure instant
On /v2/jupiter-moons, transits and occultations are what the Earth sees; shadow transits and eclipses are physical events at Jupiter that the Earth sees later. Both views are projected at the light departure instant, and the two do not coincide.
The size of that correction is not subtle. Before it was applied, all four Sun-view contacts on 2026-11-15 solved 43.9 minutes late, against an Earth-Jupiter light time of 43.89 minutes that day. The decisive test needs no reference data: near opposition a moon's shadow falls almost exactly where the moon appears, so a shadow transit must very nearly coincide with the transit. An uncorrected implementation instead reports leads of 34.0, 35.0 and 32.7 minutes for Callisto, Io and Ganymede, three moons whose sky speeds differ by a factor of seven. A geometric offset cannot be near-identical for all three; a constant equal to that day's light time can only be an uncorrected branch.
The residual that remains is published in the response, at method.light_time_residual_km: the differential light time between Jupiter and a moon is not solved separately, which is at most 0.3 s of arrival time for Callisto and moves it under 5 km.
The same response also states that the umbra is treated as a cylinder with the Sun as a point source. The Sun's angular radius at Jupiter is about 0.05 deg, so an eclipse has a penumbral fringe (367 km for Io, up to 1649 km for Callisto) and a real disappearance is gradual over roughly two to four minutes rather than instantaneous.
The sub-solar point: aberration, and a correction that is easy to double-count
The engine back-dates every position it returns, so light travel time is already in the Sun vector before /v2/libration touches it. The extra step that endpoint applies re-forms the sub-solar direction as it stood from where the Earth was one light time ago, and that is annual aberration, not a second light-time correction.
Measured at the reference instant 2026-11-14T21:30Z: the raw engine vector gives a colongitude of 334.295147, and the step as applied gives 334.300903. That is 0.005756 deg of colongitude and a direction shift of 20.7142 arcsec, against an annual aberration constant of 20.4955 arcsec, the excess being the Moon's own velocity relative to the Earth.
The response reports method.annual_aberration_applied: true with a note saying exactly that. This field previously shipped under a name that said light time, which was worse than useless: a caller reconciling this colongitude against their own ephemeris would have applied light time a second time hunting for the 0.006 deg, and never accounted for it. The arithmetic never changed; only the name did.
What is not computed, and why
A stated absence is worth more than a plausible-looking number. Each of these is published in machine-readable form as well as here.
No minor planets, no Chiron, no asteroids
The engine's body enumeration is Sun, Moon, Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune, Pluto, the solar system barycentre, the Earth-Moon barycentre, and eight user-defined star slots. There is no Chiron, no Ceres, no asteroid and no comet, and there is no way to add one without a second ephemeris. The reason is published verbatim in non_goals at /v2/conventions: the MIT-licensed Astronomy Engine has no minor-planet ephemeris, and CycleCalcs will not add a copyleft or paid ephemeris to provide one.
That is also the answer to the Swiss Ephemeris question. It is not used here. The reason is licensing, not astronomy: a copyleft or commercially licensed ephemeris would change what a caller may do with the output of this API, and the whole point of the rights statement is that the numbers come back unrestricted.
No satellites, no polar motion, no interpretation
- Satellite passes. They need TLEs that decay within days. Serving them is a permanent data-operations commitment, and a stale answer is worse than no answer.
- Polar motion. Milliarcsecond-class corrections are beyond the accuracy this API claims. Adding them would improve nothing that refraction and UT1 have not already swamped.
- Interpretation. This API returns angles, times and names. It attaches no meaning to any of them, and no field in it ever will.
Withheld pending a licence review, and named rather than blank
- The meteor catalogue. The
meteor_showersenumerated set and thenext_events.meteor_peakfield are withheld until the meteor catalogue reduction clears its licence review. Asking/v2/enums?set=meteor_showersreturns an empty set object rather than an invented one, and/v2/todaycarries the omission by name inmeta.not_computedwith the reason attached. - Star and deep-sky catalogues. The
cataloguesenumerated set is blocked while those sources go through a licence re-source. Fixed stars are still fully supported, but you supply them: pass a target of the formradec:6.7525,-16.716and the full rise, set and transit machinery works on it. There is no bundled star catalogue, and proper motion is not applied to anything. - The Saros member number on
/v2/eclipses. It needs a 223-row table of series-start epochs, which is catalogue data, and the obvious source has not cleared a provenance check. The Saros series number is closed form and is published. - Constellation genitives and the
constellationsset, which need a reduced index that has not been generated. Returning a nominative in a field labelled genitive would be worse than an honest omission.
Check any of this yourself
Every figure above came out of the shipped system, and you can get most of them back out of it without leaving your terminal. The API describes its own conventions as data, which is the point.
# the refraction block, the event definitions, the corrections register, # the date range and the non-goals, all as JSON curl "https://www.cyclecalcs.com/v2/conventions" # the delta-T model residual against the leap-second chain, at any instant curl "https://www.cyclecalcs.com/v2/time?at=2026-07-27T12:00:00Z" # the selenographic cross-check residual, in method.cross_check_residual_deg curl "https://www.cyclecalcs.com/v2/libration?at=2026-11-14T21:30:00Z&include=basic,terminator" # the Galilean light-time residual, in method.light_time_residual_km curl "https://www.cyclecalcs.com/v2/jupiter-moons?at=2026-11-15T09:40:00Z&step=1m" # the altitude a rise actually solved for, in the events array curl "https://www.cyclecalcs.com/v2/rise-set?body=moon&at=2026-06-21&lat=51.4778&lon=-0.0015" # the engine version, hash, licence and every source behind every route curl "https://www.cyclecalcs.com/v2/attribution"
The vendored engine sits in the repository unedited, so the refraction constants, the 34-arcminute allowance, the delta-T polynomial and the search tolerances quoted on this page can all be read directly from the source that computed your answer. Its hash is re-verified against the recorded upstream release on every build.
If you find a figure on this page that the shipped code does not reproduce, that is a defect and we want to hear about it: info@cyclecalcs.com. See also the API overview, the endpoint reference, the error catalogue and the engine and sources.