Your first chart data in 10 minutes
This page takes you from zero to planetary positions for a real birth moment, then shows you how to change calculation settings and what an error looks like. You need curl; jq is optional but makes the output easier to read.
1. Get a key
Section titled “1. Get a key”The API is in early access: there is no self-serve signup yet, and keys are provisioned manually. If you have been onboarded, you were issued a test key (prefix ak_test_); if not, ask your Astral contact for one. Live keys use the ak_live_ prefix — the prefix is visible in logs so you can always tell which environment a request hit.
Export the key so the examples below can use it:
export API_KEY=ak_test_your_key_hereAll requests authenticate with a single header: Authorization: Bearer $API_KEY. No OAuth, no token refresh.
2. Make the call
Section titled “2. Make the call”The subject below is a birth in New York City on May 15, 1990 at 2:30 pm Eastern Daylight Time:
curl -s https://astral-external-api-iksoi6t3nq-ue.a.run.app/v1/western/positions \ -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 } } }' | jqsubject.location is optional for this endpoint — a datetime-only subject works, and positions are identical either way. If you send coordinates, they are validated and echoed back in meta.subject_resolved.
3. Read the response
Section titled “3. Read the response”The response is the standard envelope: your results under data, provenance under meta. Abridged to a single position — the real response has one entry for each body in the resolved bodies list (by default, the ten planets plus the lunar node):
{ "data": { "positions": [ { "body": "sun", "longitude": 54.6621, "sign": "taurus", "sign_longitude": { "degrees": 24, "minutes": 39, "seconds": 44 }, "element": "earth", "modality": "fixed", "speed": 0.9581, "retrograde": false, "declination": 18.9354, "out_of_bounds": false } ] }, "meta": { "calc_version": "0.1.1", "settings_resolved": { "zodiac": "tropical", "node_type": "true", "bodies": ["sun", "moon", "…"] }, "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": 1 }}Each position
Section titled “Each position”Every celestial position, on every endpoint, uses this exact shape:
| Field | Meaning |
|---|---|
body |
Stable English key: sun, moon, mercury … pluto, plus true_node, mean_node, chiron, lilith_mean, ceres, pallas, juno, vesta. |
longitude |
Ecliptic longitude in decimal degrees (0–360). |
sign |
The zodiac sign the longitude falls in. |
sign_longitude |
The same longitude as position 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 |
Rate of motion in degrees per day. Negative means the body is moving backward through the zodiac. |
retrograde |
true when speed is negative. |
declination |
Distance north (positive) or south (negative) of the celestial equator, in decimal degrees. |
out_of_bounds |
true when the body’s declination exceeds the Sun’s maximum — the true obliquity of date (about 23.44 degrees). |
The meta envelope
Section titled “The meta envelope”meta is the provenance record. It answers “what exactly did you compute?” without a support ticket:
calc_version— the version of the numerical contract. Identical input plus identicalcalc_versionmeans identical digits, across runs and machines. If the engine’s numbers ever change, this version changes. Details in determinism and calc_version.settings_resolved— the complete settings actually used, with defaults filled in. Send nosettingsand you can see the defaults here:zodiac: "tropical",node_type: "true", and the default body list — the ten planets plus the lunar node (true_nodeby default; the response above trims the array for space). When your output differs from another provider’s, diff this object first — it is usually a defaults mismatch, not a calculation error.subject_resolved— what your subject resolved to:utc_datetime(the actual moment computed — note14:30 -04:00became18:30Z), theutc_offsetapplied, your echoedcoordinates(nullif you omitted location), andtime_known.credits_charged— what this call cost, in-band on every response. A positions call is 1 credit; you never have to reconcile a dashboard to know your burn rate.
4. Customize the calculation
Section titled “4. Customize the calculation”Everything is defaulted, everything is overridable, and whatever you send comes back resolved in meta.settings_resolved. This request switches to the sidereal zodiac with the Lahiri ayanamsa and restricts output to three bodies — and drops location entirely, since a datetime-only subject is valid:
curl -s https://astral-external-api-iksoi6t3nq-ue.a.run.app/v1/western/positions \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{ "subject": { "datetime": "1990-05-15T14:30:00-04:00" }, "settings": { "zodiac": "sidereal", "ayanamsa": "lahiri", "bodies": ["sun", "moon", "mars"] } }'meta.settings_resolved now echoes "zodiac": "sidereal" and "ayanamsa": "lahiri" — that echo is exactly what this page’s CI assertions check. The sun’s longitude shifts back by the ayanamsa (roughly 23.7 degrees in 1990), moving it from late tropical Taurus into early sidereal Taurus.
The rules are strict in both directions: ayanamsa is required when zodiac is sidereal, and rejected when it is tropical (error code settings.ayanamsa.not_applicable). node_type chooses between the true node (default) and the mean node. Unknown fields are a 400, never silently ignored.
5. When it fails
Section titled “5. When it fails”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:
curl -s https://astral-external-api-iksoi6t3nq-ue.a.run.app/v1/western/positions \ -H "Content-Type: application/json" \ -d '{"subject": {"datetime": "1990-05-15T14:30:00-04:00"}}'{ "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 and we can find the exact request in our logs. The full catalog is in the errors guide.
What’s next
Section titled “What’s next”- Authentication — key prefixes and rotation.
- Errors — the problem shape and the complete code catalog.
- Determinism and calc_version — the contract behind the digits.
- API reference — the interactive reference, rendered from the live OpenAPI spec.
API spec v0.1.0 · docs 0e4f5ec