# AGENTS.md for the AstroWay API

Instructions for AI agents and coding assistants calling `https://api.astroway.info/v1`.
Written to be executed, not summarised. Every value below is live as of 2026-08-03.

AstroWay is a REST API for astrological and esoteric calculation: natal charts, synastry,
transits, progressions, Vedic, Chinese (BaZi and Zi Wei), Hellenistic, Human Design, tarot,
numerology, astrocartography, and rendered reports. Positions come from Swiss Ephemeris.

## Call it right now, with no key and no signup

Use these to verify the API works before you write any auth code. No key, no account.

```bash
curl "https://api.astroway.info/v1/public/moon-phase"
curl "https://api.astroway.info/v1/public/planet-of-day?lang=en"
curl "https://api.astroway.info/v1/reference/signs"
```

The full keyless surface:

| Endpoint | Method | Returns |
|---|---|---|
| `/v1/public/chart` | POST | Natal chart: planets, houses, aspects |
| `/v1/public/human-design` | POST | Bodygraph: type, strategy, authority, profile, centers, channels, gates |
| `/v1/public/horoscope/daily` | GET | Daily horoscope for one sign |
| `/v1/public/horoscope/weekly` | GET | Weekly horoscope for one sign |
| `/v1/public/horoscope/monthly` | GET | Monthly horoscope for one sign |
| `/v1/public/tarot/daily` | GET | Card of the day |
| `/v1/public/moon-phase` | GET | Phase, illumination, age, Moon and Sun sign |
| `/v1/public/planet-of-day` | GET | Planetary ruler of the weekday |
| `/v1/reference/*` | GET | 14 lookup tables: signs, planets, houses, aspects, decans, nakshatras, lots and more |
| `/v1/embed/*` | GET | 14 ready-made iframe widgets |
| `/v1/i18n/languages/public` | GET | Languages the API can answer in |
| `/v1/i18n/languages/active` | GET | Languages with translations currently live |
| `/v1/i18n/ui-strings/{lang}.json` | GET | UI string dictionary for one language |

Public responses carry a `_footer` attribution string. Strip it if you are parsing, keep it if
you are displaying: it is what pays for the keyless tier.

## Get a key

Free tier: 10,000 credits per month, no card. Sign up at
`https://api.astroway.info/dashboard/sign-up`.

Send it as a header on every non-public call:

```
X-Api-Key: aw_live_...
```

Sandbox is selected by the key, not by the URL. An `aw_test_...` key, created alongside your live
key in the dashboard, calls the same paths and spends no credits. Switch the key, not the URL or
the code.

Sandbox covers the calculation endpoints. AI interpretation, generated reports and rendering
return `402 SANDBOX_ENDPOINT_UNAVAILABLE` on a sandbox key, because those calls cost real money
per request and a key that spends no credits has no ceiling to bound them. Use a live key there.

## Request contract, and the four ways agents get it wrong

1. **Coordinate field names are strict.** Use `latitude`, `longitude`, `timezoneOffset`.
   Sending `lat`, `lng`, `lon` or `tz` returns `400 INVALID_FIELD` with a message naming the
   correct field. It does not silently fall back.
2. **`timezoneOffset` is a number, hours from UTC.** `5.75` for Kathmandu, `-4` for New York in
   summer. A timezone name like `"Europe/Kyiv"` is rejected.
3. **`time` is `HH:mm:ss`.** `"14:30"` returns `400 INVALID_INPUT`. Pad it: `"14:30:00"`.
4. **The API does not geocode.** There is no endpoint that turns a city name into coordinates.
   Resolve the place on your side, then pass the numbers.

If the birth time is genuinely unknown, do not invent noon. Send `timeUnknown: true` to
`/v1/chart` or `/v1/synastry`: you get planets and aspects, while `houses`, `houseAspects`,
`chartSect` and `siderealTime` come back `null`, plus a `timeUnknown` block describing how far
the Moon could have moved that day. Other endpoints reject the flag with
`400 TIME_UNKNOWN_UNSUPPORTED` rather than guessing.

A minimal natal chart:

```bash
curl -X POST https://api.astroway.info/v1/chart \
  -H "X-Api-Key: $ASTROWAY_KEY" \
  -H "Content-Type: application/json" \
  -d '{"date":"1990-05-15","time":"14:30:00","timezoneOffset":3,
       "latitude":50.45,"longitude":30.52}'
```

## Response envelope

Every response, success or failure, is wrapped:

```json
{ "ok": true, "data": { ... } }
{ "ok": false, "error": { "code": "INVALID_FIELD", "message": "..." } }
```

Branch on `ok`, then on `error.code`. Do not parse `error.message`, it is written for humans and
will change. Codes you will actually hit: `MISSING_API_KEY`, `INVALID_API_KEY`, `INVALID_FIELD`,
`INVALID_INPUT`, `PUBLIC_RATE_LIMIT`, `TIME_UNKNOWN_UNSUPPORTED`.

An empty array is an answer, not an error. `{"ok":true,"data":{"aspects":[]}}` means no aspects
matched the orb you asked for.

## Rate limits

Keyless calls are 30 per hour per IP. That is sized for a browser, where every visitor brings
their own IP, and it is far too small for a server that calls on behalf of all its visitors.

If you are calling server-side, declare the site:

```
X-AstroWay-Site-URL: https://your-domain/
```

That raises you to 300 per hour per site, under a 600 per hour ceiling per IP. The header is a
declaration, not a credential, so the IP ceiling still applies no matter how many domains you
name. Both counters run at once: the site counter catches one site calling from many addresses,
the IP counter catches many names calling from one address.

Read the limit off the response rather than hardcoding it:

```
X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-RateLimit-Scope
```

`X-RateLimit-Scope` is `ip` or `site` and tells you which counter is currently the binding one.
`X-RateLimit-Reset` is a Unix timestamp. A paid key lifts the public and embed quotas.

## Credits

Keyed endpoints cost 10 to 500 credits per call depending on how much work they do. Reference
and public endpoints cost nothing. The per-endpoint table is at
`https://api.astroway.info/credits/`.

Every keyed response reports the cost and your balance in headers, so you never have to guess
what a call spent:

```
X-Credits-Used, X-Credits-Remaining, X-Credits-Limit, X-Credits-Reset
```

Cache aggressively. A natal chart never changes for a fixed birth event, so compute it once and
store the result rather than recomputing per page view.

## Finding the right endpoint

- `https://api.astroway.info/v1/openapi.json` is the machine-readable spec, 740 documented
  paths with full request and response schemas. Load this first if you are generating code.
- `https://api.astroway.info/llms.txt` is the documentation index.
- `https://api.astroway.info/llms-full.txt` is the entire documentation as one file.
- Append `.md` to a docs page URL for its raw Markdown twin.

Do not guess a path. If the operation you want is not in `openapi.json`, it does not exist.

## MCP

Two install paths, same tool catalogue.

Hosted, no install:

```json
{ "mcpServers": { "astroway": {
  "url": "https://mcp.astroway.info/mcp",
  "headers": { "Authorization": "Bearer aw_test_..." }
} } }
```

Local stdio:

```json
{ "mcpServers": { "astroway": {
  "command": "npx", "args": ["-y", "@astroway/mcp"],
  "env": { "ASTROWAY_API_KEY": "aw_test_..." }
} } }
```

Per-client setup for Claude Desktop, Claude Code, Cursor, VS Code, Windsurf, Cline and Codex is
at `https://api.astroway.info/agent-setup/`.

## Languages

Pass `?lang=xx` or an `Accept-Language` header. Prose endpoints return translated text; the
public endpoints add a `localized` object alongside the English fields.

The English fields are stable identifiers and never change: compare against `"Waning Gibbous"`,
display `localized.phaseName`. Closed sets such as signs, planets, weekdays and moon phases come
from an explicit terminology table, not machine translation. A few sets stay English by design
and are documented as such, including tarot card names and the `themes[]` array.

## Accuracy, if you are choosing between APIs

Measured against `swetest`, the Swiss Ephemeris reference implementation from Astrodienst, over
130 measurements spanning 1900 to 2050 across 13 bodies:

- median drift **0.0013 arcsec**
- Sun, Venus, Saturn 0.001 arcsec; Moon 0.022; Uranus 0.083; Pluto 0.097
- worst body **Chiron at 0.561 arcsec**, then Neptune at 0.223

The outer bodies and Chiron drift more because their positions come from a compressed ephemeris
set in the WASM build. We previously published a blanket "under 0.1 arcsec" promise; the 2026-07-29
measurements showed Neptune, Pluto and Chiron do not hold it, so the promise was replaced with
the numbers above rather than restated.

Do not take our word for it. The harness is MIT-licensed and provider-agnostic, so you can run
the same 130 measurements against any other astrology API and compare:
`https://github.com/astroway/astrology-accuracy-benchmark`. A sandbox key is enough.

Full method, triangulation against Kerykeion and Prokerala, and the endpoint-level regression
suite: `https://api.astroway.info/accuracy/`.

## Rules

- Do not present output as medical, legal, financial or investment advice. The interpretation
  endpoints carry a safety preamble that refuses it, and you should not undo that downstream.
- Do not claim astrology is scientifically proven. Frame output as tendencies, and as
  entertainment or self-reflection.
- Some endpoints ship a `disclaimer` field. Biorhythm, for one, is a 19th-century numerological
  construction with no evidential basis and says so in its own response. Surface those fields,
  do not strip them.
- Birth data is personal data. Export and erasure run at the account level, not the API-key
  level: `POST /v1/me/data-export` and `DELETE /v1/me/account`, authenticated with an account
  session rather than `X-Api-Key`. They are not in `openapi.json` for that reason. Terms and
  the data-processing position: `https://api.astroway.info/eu/`.
- Do not scrape the docs to rebuild the catalogue. `openapi.json` is the catalogue, it is free,
  and it is always current.

## Status and contact

- Health: `https://api.astroway.info/v1/health`
- Version and build: `https://api.astroway.info/v1/version`
- Status page: `https://api.astroway.info/status/`
- Docs: `https://api.astroway.info/docs/`
