Official PHP SDK for the AstroWay API — natal charts, synastry, transits, Vedic dashas, Tarot, Numerology, Human Design, AI horoscopes. Type-safe, retry-aware, PSR-18 compatible.
700+ endpoints. Built on Guzzle 7 + PSR-18 / PSR-7. Built-in retry on 408/409/429/5xx with exponential backoff. Stainless-style error hierarchy (AuthenticationError / RateLimitError / BadRequestError / …). PHP 8.1+.
composer require astroway/sdkGet an API key at https://api.astroway.info/dashboard/sign-up — 10 000 credits/month free, no card required. Each endpoint costs 5–500 credits depending on what it computes (pricing).
<?php
use Astroway\Astroway;
$aw = new Astroway(['apiKey' => getenv('ASTROWAY_API_KEY')]);
$chart = $aw->post('/chart', body: [
'date' => '1990-07-14',
'time' => '14:30:00',
'timezoneOffset' => 3,
'latitude' => 50.45,
'longitude' => 30.52,
'houseSystem' => 'P',
]);
$asc = $chart['angles']['asc'];
printf("ASC: %s %.2f°\n", $asc['sign'], $asc['degree']);$result = $aw->post('/synastry', body: [
'chart1' => ['date' => '1990-07-14', 'time' => '14:30:00', 'timezoneOffset' => 3, 'latitude' => 50.45, 'longitude' => 30.52],
'chart2' => ['date' => '1992-03-22', 'time' => '09:15:00', 'timezoneOffset' => 2, 'latitude' => 48.85, 'longitude' => 2.35],
]);
echo "Score: {$result['compatibility']['score']}/100 ({$result['compatibility']['label']})\n";$transits = $aw->post('/transits', body: [
'date' => '1990-07-14', 'time' => '14:30:00', 'timezoneOffset' => 3, 'latitude' => 50.45, 'longitude' => 30.52,
'targetDate' => '2027-01-01',
]);$dasha = $aw->post('/vedic/dashas/vimshottari/maha', body: [
'date' => '1985-07-22', 'time' => '06:45:00', 'timezoneOffset' => 5.5,
'latitude' => 19.07, 'longitude' => 72.87,
]);$spread = $aw->post('/tarot/rider-waite/spread', body: ['spreadType' => 'three-card', 'seed' => 42]);$hd = $aw->post('/human-design', body: [
'date' => '1990-07-14', 'time' => '14:30:00', 'timezoneOffset' => 3, 'latitude' => 50.45, 'longitude' => 30.52,
]);
echo "{$hd['type']} — {$hd['strategy']} — {$hd['authority']}\n";The SDK throws typed subclasses of Astroway\Errors\ApiError. Catch order matters — most specific first:
use Astroway\Errors\ApiError;
use Astroway\Errors\AuthenticationError;
use Astroway\Errors\BadRequestError;
use Astroway\Errors\RateLimitError;
try {
$aw->post('/chart', body: $body);
} catch (RateLimitError $e) {
sleep($e->retryAfterSeconds ?? 60);
// retry once...
} catch (AuthenticationError $e) {
throw new RuntimeException('Rotate your AstroWay API key');
} catch (BadRequestError $e) {
fwrite(STDERR, 'Validation failed: ' . json_encode($e->body) . PHP_EOL);
} catch (ApiError $e) {
fwrite(STDERR, sprintf("API error %d (%s): %s [request_id=%s]\n", $e->status, $e->errorCode, $e->getMessage(), $e->requestId));
}Full hierarchy under Astroway\Errors:
ApiError(extends\RuntimeException)APIConnectionErrorAPITimeoutError
BadRequestError(400)AuthenticationError(401)PermissionDeniedError(403)NotFoundError(404)UnprocessableEntityError(422)RateLimitError(429) — carriesretryAfterSecondsInternalServerError(5xx)
errorCode(notcode) is the AstroWay-specific error code property. The base\Exception::$codewould conflict.
$aw = new Astroway([
'apiKey' => 'aw_live_...', // required
'baseUrl' => 'https://api.astroway.info/v1', // override for staging / self-hosted
'authScheme' => 'header', // 'header' (X-Api-Key, default) or 'bearer' (Authorization: Bearer)
'timeout' => 30.0, // per-request timeout in seconds
'retry' => [
'maxRetries' => 2, // total attempts = 1 + maxRetries
'baseDelayMs' => 250,
'maxDelayMs' => 30_000,
'retryableStatuses' => [408, 409, 429, 500, 502, 503, 504],
],
'defaultHeaders' => ['X-Trace-Id' => '...'],
]);Default retry honors Retry-After (seconds or HTTP-date) on 429 responses.
Set retry: ['maxRetries' => 0] to disable retries entirely.
Two equivalent auth schemes — pick whichever your stack prefers:
- Header (default):
X-Api-Key: aw_live_...— same convention ascurl/Postman examples. - Bearer:
Authorization: Bearer aw_live_...— same convention as Stripe/OpenAI/Anthropic SDKs.
Set via 'authScheme' => 'bearer' in the constructor options.
The 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.
Outgoing requests carry two identifying headers so the AstroWay backend can distinguish SDK traffic from raw HTTP traffic in its own logs:
User-Agent: astroway-sdk-php/<version> (PHP/<php-version>; <os>)X-Astroway-Channel: sdk-php
Neither carries a session ID, machine fingerprint, or anything personal.
- Public API stable inside a major version. Methods/classes shipped under
1.xwon't be renamed or removed without a deprecation note inCHANGELOG.mdand a one-minor parallel-availability window. - Body shape stable inside a minor version. Tightening (constraints, enums) ships in patches; new required keys require a minor bump.
- API version vs SDK version are independent. SDK
0.xfollows its own semver; the API itself sits at/v1/.
- 📦 Packagist: https://packagist.org/packages/astroway/sdk
- 📘 API docs: https://api.astroway.info/docs/api/
- 🔑 Sign up & dashboard: https://api.astroway.info/dashboard/
- 💰 Pricing: https://api.astroway.info/pricing/
- 🟦 TypeScript SDK:
@astroway/sdk - 🐍 Python SDK:
astroway - 🤖 MCP server:
@astroway/mcp - 🌐 Website: https://astroway.info
MIT — see LICENSE.