Astrology API Accuracy Testing: 2,921 Gold Standard Tests
How RoxyAPI verifies astrology API accuracy: 2,921 gold standard tests pinned to NASA JPL Horizons and per-domain references, run on every deploy.
TL;DR
- RoxyAPI runs 12,106 automated tests on every deployment, and 2,921 of them are gold standard tests: each pins a value pulled from a named external authority as a hardcoded constant, for a named chart, with a stated tolerance.
- Planetary positions are verified against NASA JPL Horizons DE441. The open benchmark measured a median deviation of 1.5 arcseconds (about 0.0004 degrees) across 210 positions in 21 charts, far finer than the eye can resolve and about 0.001 percent of a zodiac sign.
- House cusps, the Ascendant and the sidereal frame are verified separately, within 1 arcsecond, because a correct planet in a wrong frame is still a wrong chart.
- None of the references runs inside RoxyAPI. They supply values that are pinned in tests; every result is computed in-process by Roxy Ephemeris.
If you are building a production astrology application, the accuracy of your data source is not a feature. It is a prerequisite. A planetary longitude that is off by one degree can shift a planet into the wrong nakshatra, cascade into incorrect dasha periods, and produce a chart an experienced astrologer rejects on sight. Yet most astrology API providers publish no testing methodology, no named reference sources and no error thresholds. They ask you to trust them.
RoxyAPI publishes the receipts instead. This article explains what a gold standard test is, which authority adjudicates which kind of claim, the exact tolerances in force, how a time-based claim like an eclipse peak or a KP crossing is verified, and how to tell a real calculation error from a convention difference. It ends with a procedure you can run yourself against NASA JPL Horizons in under five minutes, with no signup and no API key.
What does a gold standard test verify, and against what?
A gold standard test pins one value from a named external authority as a hardcoded constant, for a named chart or date, with a stated tolerance, and fails the build when RoxyAPI drifts from it. The value is pulled from the source once, recorded with its provenance, and never recomputed by the code under test. 2,921 of the 12,106 automated tests that run on every deployment are of this kind.
Gold standard tests pinned to values from named external references, out of 12,106 automated tests per deployment. Per-domain register on the methodology page.
Which authority a test pins to depends on what is being claimed, and that split is the heart of the method. NASA JPL Horizons DE441 adjudicates where a body is: its apparent geocentric ecliptic longitude at an instant. It has no house system and no sidereal zodiac, so the frame built on top of the positions, meaning house cusps, the Ascendant, the Midheaven and the ayanamsa, is verified separately against the ephemeris that professional desktop chart software computes on. Every derived layer, from dasha dates and panchang limbs to the Chinese lunisolar calendar and the Vastu mandala, is verified against the authority for that domain. The full per-domain register, naming every reference and what is checked against it, lives on the methodology page rather than here, so that one table cannot drift from another.
None of those references is part of the stack. What is taken from each source is a value: a longitude at an instant, a house cusp for a chart, an eclipse peak, a row of a printed table, recorded with its provenance and pinned as a constant. No reference runs inside RoxyAPI, is called at runtime, or is proxied, and no data file or library from any of them ships in the product. Every result is computed inside the request by Roxy Ephemeris, the in-house engine, which is also why RoxyAPI carries no copyleft obligation for the products built on it.
Ready to build on verified data? The Astrology API returns the whole calculation graph in one call, not just positions. See pricing.
How accurate are RoxyAPI planetary positions against NASA JPL Horizons?
The public benchmark measured a median deviation of 1.5 arcseconds (about 0.0004 degrees) from NASA JPL Horizons DE441 across 210 planet positions in 21 birth charts, with a mean of 2.7, a 95th percentile of 11.2 and a maximum of 16.6 arcseconds. Every one of the 210 reference points fell inside its tolerance. The maximum belongs to Neptune, the slowest body in the set; excluding Neptune and Uranus, the worst of the other eight bodies is 9.4 arcseconds.
Those numbers come from the astrology-api-benchmark repository, which is MIT licensed and ships the dataset, the reference values and the runnable code. The 21 charts include 8 named celebrity charts at AA, A and B Rodden ratings and 13 synthetic edge cases spanning 1879 to 2011, six continents, three locations above 60 degrees latitude, half-hour timezone offsets, both daylight-saving edges, the Samoa 2011 calendar skip and the Y2K rollover.
| Run date | Median | Maximum | Within tolerance | Pass bands |
|---|---|---|---|---|
| 2026-04-28 | 16.0 arcsec | 32.4 arcsec | 210 / 210 | 0.05 deg planets, 0.20 deg Moon |
| 2026-07-30 | 1.5 arcsec | 16.6 arcsec | 210 / 210 | 0.01 deg planets, 0.02 deg Moon |
Both runs are kept side by side on purpose. A benchmark that silently replaces its numbers gives a reader no way to tell a real improvement from a quiet re-tune, so the dataset and script were held fixed between the two runs and the bands were tightened after the second, not before it. The benchmark also publishes its own resolution floor, 0.36 arcseconds, because JPL Horizons prints four decimal degrees, so any figure under roughly 1 arcsecond is at the floor rather than a meaningful difference.
Why are house cusps and the sidereal frame verified separately from planets?
Because NASA JPL Horizons has no opinion about them. JPL publishes positions in the tropical frame and nothing else, so a house cusp, an Ascendant or an ayanamsa cannot be checked against it at all. RoxyAPI therefore verifies the frame against the ephemeris that professional desktop chart software runs on, and holds it to a band 36 times tighter than the planet pass band: Ascendant, Midheaven and all twelve cusps in Placidus, Koch, Equal and Whole Sign agree with that reference within 1 arcsecond across 8 charts, with a measured worst deviation of 0.13 arcseconds at the highest latitude in the set.
The sweep runs 1950 to 2049, both hemispheres, from the equator to just under the polar circle, and pins every cusp in every system, because a smoke test that passes a house system as an input and never asserts a cusp value proves nothing. A quadrant system can trisect the wrong semi-arc on four cusps while the angles stay exact, and only a test that pins all twelve numbers can see it.
The same separation holds on the sidereal side. The Lagna on the reference Vedic chart is held to 0.00004 degrees, which is 0.144 arcseconds, against a measured 0.088. That band is deliberately not sized around the residual: the Ascendant sweeps about 15 arcseconds per second of clock, so a tolerance this tight doubles as a check that the birth time and timezone were resolved correctly. Planetary sidereal longitudes on that chart are held to 0.02 degrees against the domain reference, and rashi, nakshatra and pada are asserted as exact matches with no tolerance at all, because a close nakshatra is a wrong nakshatra.
How is a time-based claim verified, like an eclipse peak or a KP crossing?
An event instant is a position claim, so RoxyAPI sizes its tolerance in arcseconds and lets the clock band follow. The error that can actually be bounded is the longitude error at the reported instant, and clock error is that divided by how fast the body moves. One arcsecond envelope is therefore a wildly different clock band per body: the Moon covers about 0.55 arcseconds a second, retrograde Saturn about 0.002, so residuals that all sit inside 16 arcseconds span 0.023 seconds to 664.6 seconds of implied clock error, a factor of 29,000.
That is why every timing test states its band in longitude, never in minutes. Every solar and lunar eclipse from 1980 to 2060, 360 events, is pinned to the reference series: the counts match exactly in both directions and the worst peak instant differs by 39.4 seconds. Eighty KP sub-lord and sign crossing instants are pinned against the frame reference and against NASA JPL Horizons, including a retrograde loop and the day the count wraps past 360 degrees. Every panchang limb boundary is checked by asking the reference what the defining quantity was at the exact instant RoxyAPI reports, so the residual is the whole error, and it sits within 1 second.
| Claim type | What is pinned | Band |
|---|---|---|
| Planetary longitude | 210 positions, 21 charts, vs NASA JPL Horizons DE441 | 0.01 deg pass band, 1.5 arcsec measured median |
| House cusps and angles | 12 cusps, 4 systems, 8 charts, 1950 to 2049 | 1 arcsec, 0.13 measured worst |
| Vedic Lagna | Reference chart, sidereal | 0.144 arcsec, 0.088 measured |
| Eclipse peak instants | 360 eclipses, 1980 to 2060 | 40 seconds, 39.4 measured worst |
| KP crossing instants | 80 sub-lord and sign crossings | Arcseconds, per body |
| Panchang limb boundaries | Tithi, nakshatra, yoga, karana | 1 second |
| Rashi, nakshatra, pada | Every graha on the reference chart | Exact match |
How do you tell a calculation error from a convention difference?
By the shape of the residual, before touching a formula. Two good implementations rarely disagree at random: a real defect and a convention mismatch leave different fingerprints across a whole chart, and reading the fingerprint locates the cause in one step. RoxyAPI prints the whole vector of differences and names the shape before sizing any tolerance, because a tolerance sized around an unexplained residual is not a regression detector.
| Signature across the chart | What it means |
|---|---|
| One uniform offset across many years | A constant error, not a structural one |
| A floor of roughly 20 arcseconds across unrelated bodies | Aberration is applied on one side and not the other |
| An offset near 17 arcseconds that wanders sign over about 18 years | Nutation is applied on one side and not the other |
| A residual constant in clock time across quantities that move at different rates | A time-scale difference (delta T), not a longitude error |
| A residual proportional to the daily motion of each body | A wrong instant, usually a source pulled with its time parameter omitted |
| Only a subset of a vector wrong while the rest is exact | One expression, not the shared pipeline |
| Angles and cusps off by arcminutes, unevenly, while every planet holds to the arcsecond | The reference chart was cast at different coordinates |
The last row is the one that reaches production support most often. A reference chart cast at the atlas position of a town, rounded to the arcminute, sits a few thousandths of a degree from the decimal coordinates an application sends. At 51 degrees north with a fast-rising sign on the horizon, 0.04 degrees of longitude moved an Ascendant by 360 arcseconds and the intermediate cusps by 135 to 214, while every planet agreed to the arcsecond. Recomputed at the same coordinates, the two charts agreed within 0.1 arcseconds. Nothing was wrong on either side; the inputs were different.
How to verify a RoxyAPI calculation against NASA JPL Horizons yourself
You do not need to trust the test suite. The procedure below reproduces one gold standard comparison end to end, on the Barack Obama chart from the public benchmark, using the same authority the suite uses. Every value shown was captured live.
- Resolve the birth place. Call
GET /location/searchand takelatitude,longitudeandtimezonefrom the first result. Thetimezoneis an IANA identifier, which the chart endpoints accept directly and resolve to the correct historical offset for the date.
curl -s "https://roxyapi.com/api/v2/location/search?q=Honolulu&limit=1" \
-H "X-API-Key: YOUR_API_KEY"
{
"cities": [
{
"city": "Honolulu",
"province": "Hawaii",
"country": "United States",
"latitude": 21.3069,
"longitude": -157.8583,
"timezone": "Pacific/Honolulu",
"utcOffset": -10
}
]
}
- Call the planets endpoint.
POST /astrology/planetsreturns the tropical ecliptic longitude of every body. Run it in the browser from the reference with no key at all, or from the terminal:
curl -X POST https://roxyapi.com/api/v2/astrology/planets \
-H "Content-Type: application/json" \
-H "X-API-Key: YOUR_API_KEY" \
-d '{"date":"1961-08-04","time":"19:24:00","latitude":21.3069,"longitude":-157.8583,"timezone":"Pacific/Honolulu"}'
{
"planets": [
{ "name": "Sun", "longitude": 132.5476605646562, "sign": "Leo", "isRetrograde": false },
{ "name": "Moon", "longitude": 63.35765353031434, "sign": "Gemini", "isRetrograde": false },
{ "name": "Mars", "longitude": 172.57679150094418, "sign": "Virgo", "isRetrograde": false },
{ "name": "Neptune", "longitude": 218.60244068277837, "sign": "Scorpio", "isRetrograde": false }
]
}
- Query NASA JPL Horizons for the same instant. 19:24 in Honolulu on 1961-08-04 is 05:24 UTC on 1961-08-05. The Horizons API is public and needs no key.
COMMANDis the body (10 is the Sun, 301 the Moon, 499 Mars, 899 Neptune),CENTER500@399is the geocentre, andQUANTITIES31 returns apparent ecliptic longitude and latitude of date, the same frame astrology uses.
curl -s -G "https://ssd.jpl.nasa.gov/api/horizons.api" \
--data-urlencode "format=text" --data-urlencode "COMMAND='10'" \
--data-urlencode "MAKE_EPHEM='YES'" --data-urlencode "EPHEM_TYPE='OBSERVER'" \
--data-urlencode "CENTER='500@399'" --data-urlencode "OBJ_DATA='NO'" \
--data-urlencode "START_TIME='1961-08-05 05:24'" --data-urlencode "STOP_TIME='1961-08-05 05:25'" \
--data-urlencode "STEP_SIZE='1'" --data-urlencode "QUANTITIES='31'"
- Compare. Subtract, multiply by 3600 for arcseconds, and read the result against the 0.01 degree pass band.
| Body | Roxy Ephemeris | NASA JPL Horizons DE441 | Difference |
|---|---|---|---|
| Sun | 132.5477 | 132.5479 | 0.89 arcsec |
| Moon | 63.3577 | 63.3574 | 0.99 arcsec |
| Mars | 172.5768 | 172.5766 | 0.73 arcsec |
| Neptune | 218.6024 | 218.6059 | 12.59 arcsec |
Neptune is the widest body here, as it is across the whole benchmark, and it still sits at a third of the pass band. Run the same four steps on any chart and any of the ten bodies, and expect the same picture.
Two traps produce a false discrepancy of 20 arcseconds or more. Horizons must be asked for the geocentre (500@399) and for apparent positions of date (QUANTITIES 31): a topocentric centre moves the Moon by up to a degree, and astrometric or J2000 columns differ from astrological longitudes by a precession term that reaches three arcminutes at a 1996 epoch.
FAQ
What tolerance is acceptable for planetary degree calculations?
RoxyAPI holds planetary longitudes to a 0.01 degree pass band against NASA JPL Horizons DE441 in the public benchmark, with a measured median of 1.5 arcseconds and a maximum of 16.6. The Moon has a 0.02 degree band because it moves about 13 degrees a day. Any provider claiming accuracy should state the band, the measured residual and the reference source, and all three should be reproducible by the reader.
How can developers independently verify astrology API accuracy?
Call POST /astrology/planets for a known chart, then query the NASA JPL Horizons API for the same UTC instant with the geocentre and apparent positions of date, and subtract. The four-step procedure on this page does that for the Barack Obama chart and shows every body within 13 arcseconds. The open astrology-api-benchmark repository automates the same comparison across 21 charts and runs against any astrology API.
Does RoxyAPI use NASA JPL Horizons at runtime?
No. NASA JPL Horizons is the verification reference, not a runtime dependency. Reference longitudes are pulled from it for named charts and pinned as constants in gold standard tests that run on every deployment. Every result an API call returns is computed in-process by Roxy Ephemeris, with no external call, data file or library from any reference.
Why is the house cusp tolerance tighter than the planet band?
Because a cusp is a convention computed from the sidereal time and latitude, not an observation, and two correct implementations of the same convention should agree almost exactly. RoxyAPI holds all twelve cusps in Placidus, Koch, Equal and Whole Sign within 1 arcsecond of the frame reference across 8 charts, with a measured worst of 0.13 arcseconds. The 0.01 degree planet band is a vendor-neutral pass bar for the open benchmark, deliberately wider than the measured 1.5 arcsecond median so that any good ephemeris can clear it.
Are Vedic and KP calculations verified against the same references as Western?
No, each layer has its own authority, and the per-domain register on the methodology page names every one. Tropical positions are verified against NASA JPL Horizons, the sidereal frame and the Lagna against the frame reference within 0.144 arcseconds, and derived Vedic output such as dasha dates, divisional charts and the panchang against the domain reference, with rashi, nakshatra and pada asserted as exact matches. KP star lords, sub lords and cuspal chains are verified against the KP reference, and eighty crossing instants against the frame reference and NASA JPL Horizons.
How often do the gold standard tests run?
On every deployment. All 12,106 automated tests, including the 2,921 gold standard tests, run before a change reaches production, and a deviation from any pinned reference value fails the build. The benchmark run history is published with dates so a reader can see when a measured figure changed and by how much.
Conclusion
Astrology API accuracy is not something to verify once and forget. It needs named authorities for each kind of claim, tolerances stated in the unit that can actually be bounded, and automated enforcement on every deployment. RoxyAPI maintains 2,921 gold standard tests on that basis and publishes the register, the benchmark and the procedure so you can check the claim rather than take it. Start with the Astrology API and see pricing.