Skip to content

Your first birth chart in 10 minutes

One call to POST /v1/western/natal returns a complete birth chart — planetary positions with house placements, house cusps and angles, an aspect scan, and chart-level distributions. This page gets you there from zero, then shows the local-time input, one settings override, and what an error looks like. You need curl; jq is optional but makes the output readable.

Keys are provisioned manually during early access. If you have been onboarded, you were issued a test key (prefix ak_test_); otherwise ask your Astral contact. Live keys use the ak_live_ prefix. Export the key so the examples below can use it:

Terminal window
export API_KEY=ak_test_your_key_here

Every request authenticates with one header: Authorization: Bearer $API_KEY. No OAuth, no token refresh.

The subject below is a birth in New York City on 15 May 1990 at 2:30 pm EDT. One call returns the composed chart:

Terminal window
curl -s https://astral-external-api-iksoi6t3nq-ue.a.run.app/v1/western/natal \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"subject": {
"datetime": "1990-05-15T14:30:00-04:00",
"location": { "latitude": 40.7128, "longitude": -74.0060 }
}
}' | jq

subject.location is required here: houses cannot be computed without coordinates. Omit it and you get a 422 with code subject.location.required; send only one of latitude/longitude and you get subject.location.incomplete.

The standard envelope puts your results under data and provenance under meta. A natal call returns five things — positions, houses, aspects, aspects_summary, and distributions. Abridged:

Response (abridged; elided values marked with …)
{
"data": {
"positions": [
{
"body": "sun",
"longitude": 54.6572,
"sign": "taurus",
"sign_longitude": { "degrees": 24, "minutes": 39, "seconds": 26 },
"element": "earth",
"modality": "fixed",
"speed": 0.9641,
"retrograde": false,
"declination": 18.936,
"out_of_bounds": false,
"house": 9
}
],
"houses": {
"house_system": "placidus",
"cusps": [ "… 12 entries: house, longitude, sign, sign_longitude …" ],
"angles": {
"ascendant": { "…": "…" },
"mc": { "…": "…" },
"descendant": { "…": "…" },
"ic": { "…": "…" },
"vertex": { "…": "…" },
"part_of_fortune": {
"longitude": 55.3228,
"sign": "taurus",
"sign_longitude": { "degrees": 25, "minutes": 19, "seconds": 22 },
"sect": "day",
"formula": "day"
}
}
},
"aspects": [
{
"type": "trine",
"body_a": "moon",
"body_b": "sun",
"angle": 120.0,
"separation": 114.1405,
"orb": 5.8595,
"applying": false,
"movement": "separating"
}
],
"aspects_summary": { "total": 19, "by_type": { "trine": 6, "…": "…" } },
"distributions": {
"elements": { "counts": { "…": "…" }, "percentages": { "…": "…" } },
"modalities": { "counts": { "…": "…" }, "percentages": { "…": "…" } },
"polarities": { "counts": { "…": "…" }, "percentages": { "…": "…" } },
"hemispheres": {
"east_west": { "east": 2, "west": 9, "dominant": "west" },
"north_south": { "north": 7, "south": 4, "dominant": "north" }
}
}
},
"meta": { "…": "see below" }
}

data.positions has one entry per resolved body — by default the ten planets plus the true node. Every position, on every endpoint, uses this shape:

Field Meaning
body Lowercase body key (sun, moon, … pluto, true_node). The full vocabulary, including asteroids, is in subjects and settings.
longitude Ecliptic longitude in decimal degrees (0–360).
sign The zodiac sign the longitude falls in.
sign_longitude The same longitude within the sign, as degrees, minutes, seconds. Decimal and DMS are always both present — you never write the conversion.
element The sign’s element: fire, earth, air, or water.
modality The sign’s modality: cardinal, fixed, or mutable.
speed Motion in degrees per day; negative means the body is retrograde.
retrograde true when speed is negative.
declination Degrees north (+) or south (−) of the celestial equator.
out_of_bounds true when the absolute declination exceeds the obliquity of date (about 23.44°).
house House (1–12) under the resolved house_system. Always present here, since location is required.

data.houses carries the resolved house_system (default placidus), twelve cusps, and six angles — ascendant, mc, descendant, ic, vertex, and part_of_fortune. Each cusp and angle uses the same longitude/sign/sign_longitude shape as a position. part_of_fortune adds sect (whether the Sun stood above or below the horizon at birth) and formula (which day/night arithmetic computed it).

data.aspects is the pairwise scan over the returned bodies, in the same shape the standalone aspects endpoint returns. Each entry gives the aspect type, the two bodies (body_a is the faster mover), the exact angle, the actual separation, the orb (deviation from exact), and movement (applying, separating, or static). In the sample, the Moon is 114.14° from the Sun — a separating trine with a 5.86° orb. data.aspects_summary gives total (19 here) plus per-type counts, so you can render a summary without walking the list.

data.distributions breaks the returned bodies down four ways: elements, modalities, and polarities (each with counts and percentages), plus hemispheres. Hemispheres are counted by house, so the block is present here and null on a location-free chart. In this chart, 9 of the 11 bodies sit in the western hemisphere and 7 in the northern.

meta records exactly what the server computed:

meta (abridged)
{
"calc_version": "0.1.1",
"settings_resolved": {
"zodiac": "tropical",
"node_type": "true",
"bodies": ["sun", "moon", "…"],
"house_system": "placidus",
"lots_formula": "sect_aware",
"aspects": {
"set": "ptolemaic",
"orbs": { "conjunction": 8.0, "opposition": 8.0, "trine": 7.0, "square": 7.0, "sextile": 5.0 }
}
},
"subject_resolved": {
"utc_datetime": "1990-05-15T18:30:00Z",
"utc_offset": "-04:00",
"coordinates": { "latitude": 40.7128, "longitude": -74.006 },
"time_known": true
},
"credits_charged": 2
}
  • calc_version — the numerical-contract version. Identical input under the same calc_version reproduces identical digits. See determinism and calc_version.
  • settings_resolved — every setting actually used, defaults filled in. Diff this object first when your output differs from another provider’s — it is usually a defaults mismatch.
  • subject_resolved — what your subject resolved to: utc_datetime (14:30 -04:00 became 18:30Z), the utc_offset applied, your echoed coordinates, and time_known.
  • credits_charged — what this call cost, in-band on every response. Natal is 2 credits. See credits and metering.

4. The easier subject: local time plus timezone

Section titled “4. The easier subject: local time plus timezone”

Birth certificates carry wall-clock time, not UTC offsets. Send local_datetime (no offset) plus an IANA timezone, and the API resolves the offset against the IANA time zone database, historical DST included:

Terminal window
curl -s https://astral-external-api-iksoi6t3nq-ue.a.run.app/v1/western/natal \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"subject": {
"local_datetime": "1990-05-15T14:30:00",
"timezone": "America/New_York",
"location": { "latitude": 40.7128, "longitude": -74.0060 }
}
}' | jq .meta.subject_resolved

This resolves to the same UTC instant as step 2 — the assertions prove it — so the chart data is byte-identical; only meta.subject_resolved.timezone is added, making the resolution visible. Local times that occurred twice (fall-back) or never occurred (spring-forward) are documented 422 errors, not guesses — see timezones and ambiguity.

Everything is defaulted, everything is overridable, and whatever you send comes back resolved in meta.settings_resolved. This request switches the house frame from Placidus to whole-sign:

Terminal window
curl -s https://astral-external-api-iksoi6t3nq-ue.a.run.app/v1/western/natal \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"subject": {
"datetime": "1990-05-15T14:30:00-04:00",
"location": { "latitude": 40.7128, "longitude": -74.0060 }
},
"settings": { "house_system": "whole_sign" }
}' | jq .data.houses.house_system

house_system accepts 22 Swiss-Ephemeris-backed systems. The other settings — zodiac and ayanamsa (sidereal charts), node_type, bodies, lots_formula, and aspects — work the same way, each with a documented default. The full catalog is in subjects and settings.

Errors are RFC 9457 problem documents (application/problem+json), and every one carries a stable machine-readable code. The cheapest way to see one is to forget the key:

Terminal window
curl -s https://astral-external-api-iksoi6t3nq-ue.a.run.app/v1/western/natal \
-H "Content-Type: application/json" \
-d '{"subject": {"datetime": "1990-05-15T14:30:00-04:00", "location": {"latitude": 40.7128, "longitude": -74.0060}}}'
401 response
{
"type": "https://docs.astralastrologyapi.com/errors/auth.missing",
"title": "Missing bearer token",
"status": 401,
"code": "auth.missing",
"detail": "send Authorization: Bearer <api key>",
"request_id": "req_f5fdf870fdd14ce8ae5e5934969e6f4f"
}

Branch on code, not on detail — codes are a versioned catalog and will not change under you; detail strings may improve over time. request_id is unique per request; include it when you contact support. The full catalog is in the errors guide.

The natal endpoint composes three single-purpose endpoints you can call directly for 1 credit each: POST /v1/western/positions, /v1/western/houses, and /v1/western/aspects. They share natal’s subject and settings schemas and the same envelope. Beyond them, these endpoints are live today:

  • Relationship charts — synastry and composite (two subjects, one shared settings object).
  • Timing — transits and transits/events, progressions, and returns (solar and lunar).
  • Sky state — moon (phase, void-of-course, next ingress, optional event window).

Full request and response schemas for all of them live in the API reference.

Guides and methodology:

API spec v0.1.0 · docs 1123b41