{"id":50359347,"url":"https://github.com/astroway/astroway-python","last_synced_at":"2026-05-30T00:04:02.611Z","repository":{"id":357468488,"uuid":"1234227263","full_name":"astroway/astroway-python","owner":"astroway","description":"Official Python SDK for the AstroWay API — sync + async clients, Pydantic models, type-safe, retry-aware, generated from OpenAPI 3.1. Natal charts,   synastry, transits, Vedic, Tarot, Human Design, AI horoscopes. Python 3.10+, py.typed.","archived":false,"fork":false,"pushed_at":"2026-05-12T22:03:44.000Z","size":224,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-13T00:08:38.098Z","etag":null,"topics":["api","astrology","astroway","async","asyncio","horoscope","httpx","human-design","natal-chart","numerology","openapi","py-typed","pydantic","python","sdk","swiss-ephemeris","synastry","tarot","type-safe","vedic-astrology"],"latest_commit_sha":null,"homepage":"https://api.astroway.info/docs/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/astroway.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-09T22:58:02.000Z","updated_at":"2026-05-12T22:03:48.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/astroway/astroway-python","commit_stats":null,"previous_names":["astroway/astroway-python"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/astroway/astroway-python","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/astroway%2Fastroway-python","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/astroway%2Fastroway-python/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/astroway%2Fastroway-python/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/astroway%2Fastroway-python/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/astroway","download_url":"https://codeload.github.com/astroway/astroway-python/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/astroway%2Fastroway-python/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33675019,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-29T02:00:06.066Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","astrology","astroway","async","asyncio","horoscope","httpx","human-design","natal-chart","numerology","openapi","py-typed","pydantic","python","sdk","swiss-ephemeris","synastry","tarot","type-safe","vedic-astrology"],"created_at":"2026-05-30T00:04:02.549Z","updated_at":"2026-05-30T00:04:02.604Z","avatar_url":"https://github.com/astroway.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# astroway\n\n\u003e Official Python SDK for the [AstroWay API](https://api.astroway.info) — natal charts, synastry, transits, Vedic dashas, Tarot, Numerology, Human Design, AI horoscopes. Sync + async, type-hinted, retry-aware.\n\n[![PyPI version](https://img.shields.io/pypi/v/astroway.svg?style=flat\u0026color=blue)](https://pypi.org/project/astroway/)\n[![Python versions](https://img.shields.io/pypi/pyversions/astroway.svg)](https://pypi.org/project/astroway/)\n[![license: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)\n\n700+ endpoints. Synchronous and asynchronous clients with the same surface. Built-in retry on 408/409/429/5xx with exponential backoff. Stainless-style error hierarchy (`AuthenticationError` / `RateLimitError` / `BadRequestError` / …). Just `httpx` + `pydantic` under the hood.\n\n---\n\n## Install\n\n```bash\npip install astroway\n# or with uv\nuv add astroway\n# or with poetry\npoetry add astroway\n```\n\nGet an API key at \u003chttps://api.astroway.info/dashboard/sign-up\u003e — **10 000 credits/month free**, no card required. Each endpoint costs 5–500 credits depending on what it computes ([pricing](https://api.astroway.info/pricing/)).\n\nRequires Python 3.9+.\n\n---\n\n## Quick start\n\n### Synchronous\n\n```python\nfrom astroway import Astroway, BirthData\n\naw = Astroway(api_key=\"aw_live_...\")\n\nchart = aw.chart.compute(BirthData(\n    date=\"1990-07-14\",\n    time=\"14:30:00\",\n    timezone_offset=3,\n    latitude=50.45,\n    longitude=30.52,\n    house_system=\"P\",\n))\n\nasc = chart[\"angles\"][\"asc\"]\nprint(f\"ASC: {asc['sign']} {asc['degree']:.2f}°\")\n```\n\n### Asynchronous\n\n```python\nimport asyncio\nfrom astroway import AsyncAstroway\n\nasync def main() -\u003e None:\n    async with AsyncAstroway(api_key=\"aw_live_...\") as aw:\n        chart = await aw.chart.compute({\n            \"date\": \"1990-07-14\",\n            \"time\": \"14:30:00\",\n            \"timezoneOffset\": 3,\n            \"latitude\": 50.45,\n            \"longitude\": 30.52,\n        })\n        print(chart[\"angles\"][\"asc\"])\n\nasyncio.run(main())\n```\n\nThe SDK exposes **103 typed namespaces / 623 methods** auto-generated from the OpenAPI spec — `aw.synastry.aspect_grid({...})`, `aw.bazi.day_master({...})`, `aw.vedic.dashas_vimshottari_maha({...})`, etc. The `{ ok, data, error }` envelope is unwrapped for you.\n\nTop-4 categories (chart, synastry, transits, vedic dashas) ship **Pydantic v2 request models** for IDE autocomplete + validation: `BirthData`, `SynastryRequest`, `TransitsRequest`, `VedicDashaRequest`. Pass either a model or a `dict` — both work everywhere.\n\nSync and async clients share an identical surface — both expose the same namespaces, plus low-level `aw.request(method, path, body=…)` / `aw.post(path, body=…)` escape hatches.\n\n---\n\n## Common workflows\n\n### Synastry\n\n```python\nfrom astroway import BirthData, SynastryRequest\n\nresult = aw.synastry.compute(SynastryRequest(\n    chart1=BirthData(date=\"1990-07-14\", time=\"14:30:00\", timezone_offset=3, latitude=50.45, longitude=30.52),\n    chart2=BirthData(date=\"1992-03-22\", time=\"09:15:00\", timezone_offset=2, latitude=48.85, longitude=2.35),\n))\nprint(f\"Score: {result['compatibility']['score']}/100 ({result['compatibility']['label']})\")\n```\n\n### Transits to natal\n\n```python\nfrom astroway import TransitsRequest\n\ntransits = aw.transits.compute(TransitsRequest(\n    date=\"1990-07-14\", time=\"14:30:00\", timezone_offset=3, latitude=50.45, longitude=30.52,\n    target_date=\"2027-01-01\",\n))\n```\n\n### Vedic Vimshottari Mahadasha\n\n```python\nfrom astroway import VedicDashaRequest\n\ndasha = aw.vedic.dashas_vimshottari_maha(VedicDashaRequest(\n    date=\"1985-07-22\", time=\"06:45:00\", timezone_offset=5.5,\n    latitude=19.07, longitude=72.87,\n))\n```\n\n### Tarot daily card\n\n```python\ncard = aw.tarot.rider_waite_daily({\"seed\": 42})\n```\n\n### Human Design\n\n```python\nhd = aw.human_design.compute({\n    \"date\": \"1990-07-14\", \"time\": \"14:30:00\", \"timezoneOffset\": 3, \"latitude\": 50.45, \"longitude\": 30.52,\n})\nprint(f\"{hd['type']} - {hd['strategy']} - {hd['authority']}\")\n```\n\n---\n\n## Error handling\n\nThe SDK raises typed subclasses of `ApiError`. Catch order matters — most specific first:\n\n```python\nfrom astroway import (\n    Astroway, ApiError,\n    AuthenticationError, RateLimitError, BadRequestError,\n)\n\ntry:\n    aw.post(\"/chart\", body=body)\nexcept RateLimitError as e:\n    time.sleep(e.retry_after_seconds or 60)\n    # retry once...\nexcept AuthenticationError:\n    raise RuntimeError(\"Rotate your AstroWay API key\")\nexcept BadRequestError as e:\n    print(\"Validation failed:\", e.body)\nexcept ApiError as e:\n    print(f\"API error {e.status} ({e.code}): {e!s} [request_id={e.request_id}]\")\n```\n\nFull hierarchy:\n\n- `ApiError` (base)\n  - `APIConnectionError`\n    - `APITimeoutError`\n  - `BadRequestError` (400)\n  - `AuthenticationError` (401)\n  - `PermissionDeniedError` (403)\n  - `NotFoundError` (404)\n  - `UnprocessableEntityError` (422)\n  - `RateLimitError` (429) — carries `retry_after_seconds`\n  - `InternalServerError` (5xx)\n\n---\n\n## Configuration\n\n```python\naw = Astroway(\n    api_key=\"aw_live_...\",                  # required\n    base_url=\"https://api.astroway.info/v1\", # override for staging / self-hosted\n    auth_scheme=\"header\",                    # \"header\" (X-Api-Key, default) or \"bearer\" (Authorization: Bearer)\n    timeout=30.0,                            # per-request timeout in seconds\n    retry={\n        \"max_retries\": 2,                    # total attempts = 1 + max_retries\n        \"base_delay_ms\": 250,\n        \"max_delay_ms\": 30_000,\n        \"retryable_statuses\": frozenset({408, 409, 429, 500, 502, 503, 504}),\n    },\n    default_headers={\"X-Trace-Id\": \"...\"},\n)\n```\n\nThe default retry honors `Retry-After` (seconds or HTTP-date) on 429 responses.\n\nSet `retry={\"max_retries\": 0}` to disable retries entirely.\n\n---\n\n## Authentication\n\nTwo equivalent auth schemes — pick whichever your stack prefers:\n\n- **Header (default):** `X-Api-Key: aw_live_...` — same convention as `curl`/Postman examples.\n- **Bearer:** `Authorization: Bearer aw_live_...` — same convention as Stripe/OpenAI/Anthropic SDKs.\n\nSet via `auth_scheme=\"bearer\"` in the constructor.\n\n---\n\n## Privacy\n\nThe SDK does **not** phone home. There is no telemetry, no analytics, no usage reporting. The only network traffic the SDK originates is the AstroWay API calls you ask it to make.\n\nOutgoing requests carry two identifying headers so the AstroWay backend can distinguish SDK traffic from raw HTTP traffic in its own logs:\n\n- `User-Agent: astroway-sdk-python/\u003cversion\u003e (Python/\u003cpy-version\u003e; \u003cplatform\u003e)`\n- `X-Astroway-Channel: sdk-py`\n\nNeither carries a session ID, machine fingerprint, or anything personal.\n\n---\n\n## Stability\n\nSince **`1.0.0` (2026-05-11)** this package follows strict SemVer:\n\n- **Public names in `astroway.__all__` stable inside `1.x`.** Removing or narrowing requires a `2.0.0` major bump with deprecation period.\n- **Method signatures stable inside `1.x`.** Adding a new keyword-only parameter (with default) is non-breaking; reordering or renaming is breaking.\n- **Body shape stable inside `1.minor`.** Tightening (constraints, enum) ships in patches; new required keys require a minor bump.\n- **API version vs SDK version are independent.** SDK `1.x` follows its own semver; the API itself sits at `/v1/`.\n- **Python 3.10+ required** since `1.0.0`. Need 3.9? Stay on `0.x` (will receive critical security patches).\n\n### Migration from `0.1.0a1` … `0.1.0rc1` to `0.1.0`\n\n`0.1.0` freezes the public surface. **No breaking changes** vs `0.1.0rc1` — every export, namespace, error class, and option added across alphas / betas / RCs ships unchanged. The freeze means future `0.1.x` patches will not narrow types or remove names; that level of change requires a `0.2.0` minor bump.\n\n| Coming from | Action |\n|---|---|\n| `0.1.0a1` (manual `aw.post('/chart', body=...)`) | Switch to typed namespaces — `aw.chart.compute(body)`, `aw.synastry.aspect_grid(body)`, etc. The escape hatch (`aw.request(...)`) still works. |\n| `0.1.0a2` … `a3` (no idempotency / errors) | Pick up automatic `Idempotency-Key` on POSTs, `error.request_id` / `error.credits_remaining` getters, Pydantic models for top categories. |\n| `0.1.0a4` … `a6` (no helpers) | `from astroway.helpers import BirthDateTime` for `from_city()` / `from_coordinates()`. |\n| `0.1.0b1` … `b3` (no streaming / cache / mock) | `for chunk in aw.charts.compute(...).stream()`, `Astroway(cache=MemoryCache())`, `from astroway.testing import MockAstroway`. |\n| `0.1.0rc1` (no bring-your-own httpx) | Optional: pass `http_client=httpx.Client(...)`, `limits=httpx.Limits(...)`, or `transport='aiohttp'` (with `pip install astroway[aiohttp]`). |\n\nA type-stability test suite (`tests/test_types.py`) inspects constructor signatures, error subclass tree, dataclass fields, and Literal unions — any future PR that breaks the public surface fails CI before reaching PyPI.\n\n---\n\n## Links\n\n- 📦 PyPI: \u003chttps://pypi.org/project/astroway/\u003e\n- 📘 API docs: \u003chttps://api.astroway.info/docs/api/\u003e\n- 🔑 Sign up \u0026 dashboard: \u003chttps://api.astroway.info/dashboard/\u003e\n- 💰 Pricing: \u003chttps://api.astroway.info/pricing/\u003e\n- 🟦 TypeScript SDK: [`@astroway/sdk`](https://www.npmjs.com/package/@astroway/sdk)\n- 🤖 MCP server: [`@astroway/mcp`](https://www.npmjs.com/package/@astroway/mcp)\n- 🌐 Website: \u003chttps://astroway.info\u003e\n\n---\n\n## License\n\nMIT — see [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fastroway%2Fastroway-python","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fastroway%2Fastroway-python","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fastroway%2Fastroway-python/lists"}