{"id":50358805,"url":"https://github.com/astroway/astroway-php","last_synced_at":"2026-05-30T00:02:14.565Z","repository":{"id":357468464,"uuid":"1234231167","full_name":"astroway/astroway-php","owner":"astroway","description":"Official PHP SDK for the AstroWay API — PSR-18 HTTP client (BYO Guzzle/Symfony/Nyholm), DTOs, mock client, PSR-3 logger, Guzzle promises concurrency.    Natal, synastry, transits, Vedic, Tarot, Human Design, AI horoscopes. PHP 8.2+.","archived":false,"fork":false,"pushed_at":"2026-05-12T22:14:07.000Z","size":100,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-13T00:08:24.489Z","etag":null,"topics":["api","astrology","astroway","composer","guzzle","horoscope","human-design","natal-chart","numerology","openapi","packagist","php","psr-18","psr-3","psr-7","sdk","swiss-ephemeris","synastry","tarot","vedic-astrology"],"latest_commit_sha":null,"homepage":"https://api.astroway.info/docs/","language":"PHP","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-09T23:07:14.000Z","updated_at":"2026-05-12T22:03:35.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/astroway/astroway-php","commit_stats":null,"previous_names":["astroway/astroway-php"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/astroway/astroway-php","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/astroway%2Fastroway-php","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/astroway%2Fastroway-php/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/astroway%2Fastroway-php/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/astroway%2Fastroway-php/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/astroway","download_url":"https://codeload.github.com/astroway/astroway-php/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/astroway%2Fastroway-php/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","composer","guzzle","horoscope","human-design","natal-chart","numerology","openapi","packagist","php","psr-18","psr-3","psr-7","sdk","swiss-ephemeris","synastry","tarot","vedic-astrology"],"created_at":"2026-05-30T00:02:13.812Z","updated_at":"2026-05-30T00:02:14.558Z","avatar_url":"https://github.com/astroway.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# astroway/sdk\n\n\u003e Official PHP SDK for the [AstroWay API](https://api.astroway.info) — natal charts, synastry, transits, Vedic dashas, Tarot, Numerology, Human Design, AI horoscopes. Type-safe, retry-aware, PSR-18 compatible.\n\n[![Latest Version](https://img.shields.io/packagist/v/astroway/sdk.svg?style=flat\u0026color=blue)](https://packagist.org/packages/astroway/sdk)\n[![PHP version](https://img.shields.io/packagist/php-v/astroway/sdk.svg)](https://packagist.org/packages/astroway/sdk)\n[![license: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)\n\n700+ endpoints. Pure **PSR-18 / PSR-17** — bring your own HTTP client (Guzzle, Symfony, Buzz, …) or let auto-discovery pick one. Built-in retry on 408/409/429/5xx with exponential backoff. Stainless-style error hierarchy (`AuthenticationError` / `RateLimitError` / `BadRequestError` / …). PHP 8.1+.\n\n---\n\n## Install\n\n```bash\ncomposer require astroway/sdk\n```\n\nThe SDK requires a PSR-18 HTTP client. If you don't already have one, the simplest path is:\n\n```bash\ncomposer require guzzlehttp/guzzle nyholm/psr7\n```\n\nAlready using Symfony's HTTP client, Buzz, or another PSR-18 implementation? `php-http/discovery` (a transitive dep of this SDK) auto-finds it. Or pass it explicitly:\n\n```php\n$aw = new Astroway([\n    'apiKey'        =\u003e getenv('ASTROWAY_API_KEY'),\n    'httpClient'    =\u003e $myPsr18Client,    // any Psr\\Http\\Client\\ClientInterface\n    'requestFactory'=\u003e $myRequestFactory, // optional Psr\\Http\\Message\\RequestFactoryInterface\n    'streamFactory' =\u003e $myStreamFactory,  // optional Psr\\Http\\Message\\StreamFactoryInterface\n]);\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\n---\n\n## Quick start\n\n```php\n\u003c?php\n\nuse Astroway\\Astroway;\n\n$aw = new Astroway(['apiKey' =\u003e getenv('ASTROWAY_API_KEY')]);\n\n$chart = $aw-\u003echart()-\u003ecompute([\n    'date' =\u003e '1990-07-14',\n    'time' =\u003e '14:30:00',\n    'timezoneOffset' =\u003e 3,\n    'latitude' =\u003e 50.45,\n    'longitude' =\u003e 30.52,\n    'houseSystem' =\u003e 'P',\n]);\n\n$asc = $chart['angles']['asc'];\nprintf(\"ASC: %s %.2f°\\n\", $asc['sign'], $asc['degree']);\n```\n\nThe SDK exposes **103 typed service namespaces / 623 methods** auto-generated from the OpenAPI spec — `$aw-\u003esynastry()-\u003easpectGrid([...])`, `$aw-\u003ebazi()-\u003edayMaster([...])`, `$aw-\u003evedic()-\u003edashasVimshottariMaha([...])`, etc. The `{ ok, data, error }` envelope is unwrapped for you. Service objects are memoized per Astroway instance.\n\nNeed a raw response or an endpoint not yet covered by services? `$aw-\u003erequest('POST', $path, ['json' =\u003e $body])` and `$aw-\u003epost($path, body: …)` remain available as escape hatches.\n\n---\n\n## Common workflows\n\n### Synastry\n\n```php\n$result = $aw-\u003esynastry()-\u003ecompute([\n    'chart1' =\u003e ['date' =\u003e '1990-07-14', 'time' =\u003e '14:30:00', 'timezoneOffset' =\u003e 3, 'latitude' =\u003e 50.45, 'longitude' =\u003e 30.52],\n    'chart2' =\u003e ['date' =\u003e '1992-03-22', 'time' =\u003e '09:15:00', 'timezoneOffset' =\u003e 2, 'latitude' =\u003e 48.85, 'longitude' =\u003e 2.35],\n]);\necho \"Score: {$result['compatibility']['score']}/100 ({$result['compatibility']['label']})\\n\";\n```\n\n### Transits to natal\n\n```php\n$transits = $aw-\u003etransits()-\u003ecompute([\n    'date' =\u003e '1990-07-14', 'time' =\u003e '14:30:00', 'timezoneOffset' =\u003e 3, 'latitude' =\u003e 50.45, 'longitude' =\u003e 30.52,\n    'targetDate' =\u003e '2027-01-01',\n]);\n```\n\n### Vedic Vimshottari Mahadasha\n\n```php\n$dasha = $aw-\u003evedic()-\u003edashasVimshottariMaha([\n    'date' =\u003e '1985-07-22', 'time' =\u003e '06:45:00', 'timezoneOffset' =\u003e 5.5,\n    'latitude' =\u003e 19.07, 'longitude' =\u003e 72.87,\n]);\n```\n\n### Tarot daily card\n\n```php\n$card = $aw-\u003etarot()-\u003eriderWaiteDaily(['seed' =\u003e 42]);\n```\n\n### Human Design\n\n```php\n$hd = $aw-\u003ehumanDesign()-\u003ecompute([\n    'date' =\u003e '1990-07-14', 'time' =\u003e '14:30:00', 'timezoneOffset' =\u003e 3, 'latitude' =\u003e 50.45, 'longitude' =\u003e 30.52,\n]);\necho \"{$hd['type']} — {$hd['strategy']} — {$hd['authority']}\\n\";\n```\n\n---\n\n## Error handling\n\nThe SDK throws typed subclasses of `Astroway\\Errors\\ApiError`. Catch order matters — most specific first:\n\n```php\nuse Astroway\\Errors\\ApiError;\nuse Astroway\\Errors\\AuthenticationError;\nuse Astroway\\Errors\\BadRequestError;\nuse Astroway\\Errors\\RateLimitError;\n\ntry {\n    $aw-\u003epost('/chart', body: $body);\n} catch (RateLimitError $e) {\n    sleep($e-\u003eretryAfterSeconds ?? 60);\n    // retry once...\n} catch (AuthenticationError $e) {\n    throw new RuntimeException('Rotate your AstroWay API key');\n} catch (BadRequestError $e) {\n    fwrite(STDERR, 'Validation failed: ' . json_encode($e-\u003ebody) . PHP_EOL);\n} catch (ApiError $e) {\n    fwrite(STDERR, sprintf(\"API error %d (%s): %s [request_id=%s]\\n\", $e-\u003estatus, $e-\u003eerrorCode, $e-\u003egetMessage(), $e-\u003erequestId));\n}\n```\n\nFull hierarchy under `Astroway\\Errors`:\n\n- `ApiError` (extends `\\RuntimeException`)\n  - `APIConnectionError`\n    - `APITimeoutError`\n  - `BadRequestError` (400)\n  - `AuthenticationError` (401)\n  - `PermissionDeniedError` (403)\n  - `NotFoundError` (404)\n  - `UnprocessableEntityError` (422)\n  - `RateLimitError` (429) — carries `retryAfterSeconds`\n  - `InternalServerError` (5xx)\n\n\u003e `errorCode` (not `code`) is the AstroWay-specific error code property. The base `\\Exception::$code` would conflict.\n\n---\n\n## Configuration\n\n```php\n$aw = new Astroway([\n    'apiKey'         =\u003e 'aw_live_...',               // required\n    'baseUrl'        =\u003e 'https://api.astroway.info/v1', // override for staging / self-hosted\n    'authScheme'     =\u003e 'header',                    // 'header' (X-Api-Key, default) or 'bearer' (Authorization: Bearer)\n    'retry'          =\u003e [\n        'maxRetries'        =\u003e 2,                    // total attempts = 1 + maxRetries\n        'baseDelayMs'       =\u003e 250,\n        'maxDelayMs'        =\u003e 30_000,\n        'retryableStatuses' =\u003e [408, 409, 429, 500, 502, 503, 504],\n    ],\n    'defaultHeaders' =\u003e ['X-Trace-Id' =\u003e '...'],\n    'httpClient'     =\u003e null,    // any PSR-18 ClientInterface (auto-discovered if omitted)\n    'requestFactory' =\u003e null,    // any PSR-17 RequestFactoryInterface (auto-discovered)\n    'streamFactory'  =\u003e null,    // any PSR-17 StreamFactoryInterface (auto-discovered)\n]);\n```\n\nDefault retry honors `Retry-After` (seconds or HTTP-date) on 429 responses.\n\nSet `retry: ['maxRetries' =\u003e 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 `'authScheme' =\u003e 'bearer'` in the constructor options.\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-php/\u003cversion\u003e (PHP/\u003cphp-version\u003e; \u003cos\u003e)`\n- `X-Astroway-Channel: sdk-php`\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 `Astroway` surface stable inside `1.x`** — constructor `$options` shape, `request/get/post/put/delete/concurrent` methods, 100+ namespace accessors (`chart()`, `synastry()`, ...), `ApiError` public properties (`status`/`errorCode`/`requestId`/`creditsRemaining`/`retryAfterSeconds`/`body`). Removing or renaming any of them requires `2.0.0` with deprecation period.\n- **Error subclass tree stable inside `1.x`** — 9 classified `*Error` subtypes are part of the contract.\n- **Body shape stable inside `1.minor`.** Tightening (constraints, enums) 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- **PHP 8.2+ required** since `1.0.0`. Need 8.1? Stay on `0.x` (will receive critical security patches).\n\n### Migration from `0.1.0-alpha.x` / `0.1.0-beta.x` / `0.1.0-rc.1` to `0.1.0`\n\n`0.1.0` freezes the public surface. **No breaking changes** vs `0.1.0-rc.1` — every export, namespace, error class, and option added across alphas / betas / RC ships unchanged. The freeze means future `0.1.x` patches will not narrow types, remove classes, or rename methods; that level of change requires a `0.2.0` minor bump.\n\n| Coming from | Action |\n|---|---|\n| `0.1.0-alpha.1` (hard Guzzle dependency) | Now PSR-18 — bring your own client (`'httpClient' =\u003e $client`) or rely on auto-discovery via `php-http/discovery`. |\n| `0.1.0-alpha.2` … `alpha.4` (no service classes / DTOs) | Switch to typed services (`$aw-\u003echart()-\u003ecompute($body)`, etc.) and DTO classes (`new NatalChartRequest(...)`). The escape hatch (`$aw-\u003epost('/chart', $body)`) still works. |\n| `0.1.0-alpha.5` … `alpha.6` (no error refinement / idempotency) | Catch `RateLimitException` / `QuotaExceededException` separately; `$exception-\u003erequestId` / `creditsRemaining` / `retryAfterSeconds` available. Auto `Idempotency-Key` on POSTs. |\n| `0.1.0-beta.1` … `beta.3` (no helpers / cache / concurrent) | `BirthDateTime::fromCity(...)` helpers; PSR-16 cache via `'cache' =\u003e $cache`; `$aw-\u003econcurrent(10)-\u003eall([...])` for parallel batches. |\n| `0.1.0-beta.4` (no mock client) | `use Astroway\\Testing\\MockAstroway;` for PHPUnit — drop-in for `Astroway`. |\n| `0.1.0-rc.1` (no logger / metrics) | Optional: pass `'logger' =\u003e $monolog` and `'metrics' =\u003e fn($e) =\u003e ...` for PSR-3 + observability. |\n\nA surface-lock test suite (`tests/SurfaceLockTest.php`) uses Reflection to assert public method signatures, error subclass tree, and namespace accessor presence — any future PR that breaks the public surface fails CI before reaching Packagist. `phpstan analyse` is also clean at level 6.\n\n---\n\n## Links\n\n- 📦 Packagist: \u003chttps://packagist.org/packages/astroway/sdk\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- 🐍 Python SDK: [`astroway`](https://pypi.org/project/astroway/)\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-php","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fastroway%2Fastroway-php","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fastroway%2Fastroway-php/lists"}