:::note
**TL;DR**
- One Composer package, `roxyapi/sdk`, ships on Packagist today and covers Western astrology, Vedic kundli, panchang, tarot, numerology, biorhythm, I Ching, crystals, dreams, angel numbers, and location across 131 endpoints.
- Install with `composer require roxyapi/sdk`. Requires PHP 8.2+. One dependency, Saloon v4.
- Geocode the birth city with `$roxy->location->searchCities` first. Feed `latitude`, `longitude`, and `timezone` into every chart, panchang, dasha, or natal call.
- Works in Laravel, Symfony, Slim, WordPress, and vanilla PHP. Build a multi-domain insight app this afternoon with the [astrology API](/products/astrology-api "production-ready astrology API with natal charts, transits, synastry, and daily horoscopes").
:::

The new RoxyAPI PHP SDK published to Packagist today as `roxyapi/sdk` v0.1.1. One Composer install gives every PHP project the same surface the TypeScript and Python SDKs already ship: Western astrology, Vedic astrology, numerology, tarot, biorhythm, I Ching, crystals, dreams, angel numbers, location, plus usage and language helpers. Methods are named arguments, responses are plain associative arrays, and the only runtime dependency is Saloon v4. This post is the launch note and a hands-on tutorial: by the end you will have a small PHP app that calls multiple RoxyAPI domains and returns JSON ready for any frontend.

## What does the new PHP SDK cover, and why ship one now

`roxyapi/sdk` is the third sibling in the RoxyAPI client family, after `@roxyapi/sdk` on npm and `roxy-sdk` on PyPI. The PHP version covers the same 131 endpoints across 12 domains under one API key. PHP runs the largest CMS and e-commerce footprint on the web (WordPress, Drupal, Magento), and the Laravel and Symfony ecosystems keep growing. Shipping a typed PHP SDK closes the last big gap in the agent-and-app stack. The package depends only on [Saloon v4](https://docs.saloon.dev/), the modern PHP HTTP SDK framework, plus PHP 8.2 named arguments.

| Property | Endpoints | What it covers |
|---|---|---|
| `$roxy->astrology` | 22 | Western natal charts, transits, synastry, daily, weekly, and monthly horoscopes |
| `$roxy->vedicAstrology` | 42 | Kundli, panchang, dasha, dosha, KP system, navamsa, Guna Milan |
| `$roxy->numerology` | 16 | Life Path, Expression, Soul Urge, Personal Year, compatibility |
| `$roxy->tarot` | 10 | Daily card, Celtic Cross, three-card, love, yes-no, card catalog |
| `$roxy->biorhythm` | 6 | Daily, forecast, compatibility, critical days |
| `$roxy->iching` | 9 | Daily hexagram, cast, 64 hexagrams catalog |
| `$roxy->crystals` | 12 | By zodiac, chakra, birthstone, free-text search |
| `$roxy->dreams` | 5 | Symbol lookup, daily symbol |
| `$roxy->angelNumbers` | 4 | Sequence meanings, daily, universal lookup |
| `$roxy->location` | 3 | City search and geocoding |
| `$roxy->usage` / `$roxy->languages` | 2 | Quota stats and the eight `lang` codes |

Ready to build with this? [Astrology API](/products/astrology-api "production-ready astrology API with natal charts, transits, synastry, and daily horoscopes") and [Vedic Astrology API](/products/vedic-astrology-api "production-ready Vedic Astrology API with kundli, panchang, dashas, and KP") run under one key. [See pricing](/pricing "RoxyAPI pricing and plan tiers").

## How to install the PHP SDK and authenticate in two minutes

Pull the package with Composer, then resolve a `Roxy` connector through the `createRoxy` factory. The factory sets the base URL (`https://roxyapi.com/api/v2`) and the `X-API-Key` header on every outgoing request, so application code never builds an HTTP client by hand. Get a key at [pricing](/pricing "RoxyAPI pricing and plan tiers"); every plan includes every domain. Export the key as an environment variable rather than hard-coding it. PHP picks it up via `getenv` in any framework.

```bash
composer require roxyapi/sdk
```

```php
<?php
require __DIR__ . '/vendor/autoload.php';

use function RoxyAPI\Sdk\createRoxy;

$roxy = createRoxy(getenv('ROXY_API_KEY'));

// First call: no body, no coordinates, just a sign
$horoscope = $roxy->astrology->getDailyHoroscope(sign: 'aries');
echo $horoscope['overview'], PHP_EOL;
echo 'Energy rating: ', $horoscope['energyRating'], "/10", PHP_EOL;
echo 'Lucky number: ', $horoscope['luckyNumber'], PHP_EOL;
```

The package lives at [packagist.org/packages/roxyapi/sdk](https://packagist.org/packages/roxyapi/sdk) and the source is at [github.com/RoxyAPI/sdk-php](https://github.com/RoxyAPI/sdk-php). Every method returns `array<string, mixed>` decoded from the API response, or throws `RoxyAPI\Sdk\RoxyApiException` on any 4xx or 5xx. Access response fields with `$result['key']['subkey']`. Object syntax like `$result->key` throws a runtime `Attempt to read property` error because the SDK never returns objects on the success path.

## How to geocode a birth city and generate a Vedic kundli

Every chart, panchang, dasha, dosha, navamsa, KP, synastry, compatibility-score, and natal endpoint needs `latitude`, `longitude`, and `timezone`. Never ask a user to type coordinates. Call `$roxy->location->searchCities` first, take the first hit, and feed `latitude`, `longitude`, and `timezone` into the chart method. The `timezone` field on the city is the IANA identifier (`Asia/Kolkata`, `America/New_York`), and chart endpoints accept both the IANA string and the decimal `utcOffset` (`5.5`, `-5`) on the same call. The server resolves the IANA string to the DST-correct offset for the chart `date`, so a winter birth in New York returns EST and a summer birth returns EDT without caller-side date math.

```php
// Step 1: geocode
$result = $roxy->location->searchCities(q: 'Mumbai');
['latitude' => $lat, 'longitude' => $lon, 'timezone' => $tz] = $result['cities'][0];

// Step 2: generate the kundli
$kundli = $roxy->vedicAstrology->generateBirthChart(
    date: '1990-01-15',
    time: '14:30:00',
    latitude: $lat,
    longitude: $lon,
    timezone: $tz,
);

// Look up any planet by name on the meta dict
echo $kundli['meta']['Sun']['rashi'], "\n";              // e.g. "Capricorn"
echo $kundli['meta']['Moon']['nakshatra']['name'], "\n"; // e.g. "Uttara Ashadha"
echo 'Pada: ', $kundli['meta']['Moon']['nakshatra']['pada'], "\n";

// Iterate the rashi houses for the 12-sign chart
foreach (['aries','taurus','gemini','cancer','leo','virgo',
          'libra','scorpio','sagittarius','capricorn','aquarius','pisces'] as $rashi) {
    foreach ($kundli[$rashi]['signs'] ?? [] as $planet) {
        echo $rashi, ': ', $planet['graha'], "\n";
    }
}
```

The Vedic response is where the depth lives. Each planet on the `meta` dict carries `graha`, `rashi`, `longitude`, `nakshatra.name`, `nakshatra.pada`, `nakshatra.key`, and `isRetrograde`. The full [Vedic astrology API reference](/api-reference#tag/vedic-astrology "full Vedic astrology API reference with kundli, panchang, dasha, and KP schemas") documents every field, and the [`POST /vedic-astrology/birth-chart`](/api-reference#tag/vedic-astrology/POST/vedic-astrology/birth-chart "Vedic birth chart endpoint with kundli, meta, and combustion fields") lands directly on the playground.

## How to combine domains in a single multi-insight call

Multi-domain readings are the unlock that single-purpose APIs cannot match. Once the connector is wired, computing a numerology Life Path, a daily tarot card, and a Western natal chart for the same user is three method calls on the same `$roxy` instance. Each domain hangs off a property on the connector, each method maps to one operationId in the spec, and each response is a plain array. The pattern below builds the data layer for a full insight profile; a frontend hits one PHP endpoint and gets every domain back in one JSON document.

```php
function buildProfile(\RoxyAPI\Sdk\Roxy $roxy, string $city, array $birth): array
{
    $cities = $roxy->location->searchCities(q: $city);
    $loc = $cities['cities'][0];

    return [
        'lifePath' => $roxy->numerology->calculateLifePath(
            year:  $birth['year'],
            month: $birth['month'],
            day:   $birth['day'],
        ),
        'dailyCard' => $roxy->tarot->getDailyCard(seed: $birth['user_id']),
        'natalChart' => $roxy->astrology->generateNatalChart(
            date:      sprintf('%04d-%02d-%02d', $birth['year'], $birth['month'], $birth['day']),
            time:      $birth['time'],
            latitude:  $loc['latitude'],
            longitude: $loc['longitude'],
            timezone:  $loc['timezone'],
        ),
    ];
}

$profile = buildProfile($roxy, 'Mumbai', [
    'year' => 1990, 'month' => 1, 'day' => 15,
    'time' => '14:30:00', 'user_id' => 'user-42',
]);

echo 'Life Path: ', $profile['lifePath']['number'], "\n";
echo 'Today: ', $profile['dailyCard']['card']['name'],
     ($profile['dailyCard']['card']['reversed'] ? ' (reversed)' : ''), "\n";
echo 'Ascendant: ', $profile['natalChart']['ascendant']['sign'], "\n";
echo 'Sun: ', $profile['natalChart']['planets'][0]['sign'] ?? '?', "\n";
```

Sub-objects on responses are arrays, not scalars. `$chart['ascendant']` is `['sign' => ..., 'degree' => ..., 'longitude' => ...]`, not a string. Drilling in (`$chart['ascendant']['sign']`) is required. The same rule applies to `meta.{Planet}.nakshatra` on the Vedic chart and `card` on the tarot daily.

## How to wire the SDK into Laravel, Symfony, or vanilla PHP

The SDK is framework-agnostic because Composer autoload runs everywhere a PHP project does. The same `roxyapi/sdk` install works in Laravel, Symfony, Slim, Lumen, WordPress (via `composer require`), and a single `index.php`. Laravel users register the connector once as a singleton in a service provider, then inject `RoxyAPI\Sdk\Roxy` into any controller. Symfony users wire the same singleton through `services.yaml`. Vanilla PHP users call `createRoxy` directly at the top of any script.

```php
// app/Providers/RoxyServiceProvider.php
namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use RoxyAPI\Sdk\Roxy;
use function RoxyAPI\Sdk\createRoxy;

class RoxyServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        $this->app->singleton(Roxy::class, function () {
            $key = (string) config('services.roxyapi.key', env('ROXY_API_KEY', ''));
            if ('' === $key) {
                throw new \RuntimeException('ROXY_API_KEY is not configured.');
            }
            return createRoxy($key);
        });
    }
}
```

Add the matching entry to `config/services.php` (`'roxyapi' => ['key' => env('ROXY_API_KEY')]`) and the connector resolves from the container.

```php
// app/Http/Controllers/HoroscopeController.php
use RoxyAPI\Sdk\Roxy;

class HoroscopeController extends Controller
{
    public function show(Roxy $roxy, string $sign)
    {
        return $roxy->astrology->getDailyHoroscope(sign: $sign);
    }
}
```

Laravel returns the array as JSON automatically. The same connector works inside a queue job, an Artisan command, or a scheduled task. For WordPress plugins or themes that already load Composer (or load it via the `roxyapi-sdk-wordpress` plugin), call `createRoxy(get_option('roxy_api_key'))` from a backend handler, never from a shortcode that runs on the client. For the full WordPress pattern, see the [WordPress integration guide](/docs/integrations/wordpress "RoxyAPI WordPress integration with shortcodes and REST routes").

## How to render the JSON in a browser and handle errors

The SDK returns JSON. Rendering belongs in the browser. The recommended path is [@roxyapi/ui](https://github.com/RoxyAPI/ui), the open-source web component library: PHP fetches the JSON, the browser hands it to a `<roxy-natal-chart>` or `<roxy-tarot-card>` element, and the wheel or card renders without any PHP templating. The same components work in WordPress shortcodes, Shopify themes, plain HTML, and React projects. The pattern below is the full server-plus-browser loop from the SDK examples directory.

```php
// /api/natal-chart.php
require __DIR__ . '/../vendor/autoload.php';

use function RoxyAPI\Sdk\createRoxy;
use RoxyAPI\Sdk\RoxyApiException;

header('Content-Type: application/json');
$roxy = createRoxy(getenv('ROXY_API_KEY'));

try {
    echo json_encode($roxy->astrology->generateNatalChart(
        date:      $_GET['date'],
        time:      $_GET['time'],
        latitude:  (float) $_GET['lat'],
        longitude: (float) $_GET['lon'],
        timezone:  is_numeric($_GET['tz']) ? (float) $_GET['tz'] : $_GET['tz'],
    ));
} catch (RoxyApiException $e) {
    http_response_code($e->statusCode);
    echo json_encode(['error' => $e->error, 'code' => $e->errorCode]);
}
```

```html
<script type="module"
  src="https://cdn.jsdelivr.net/npm/@roxyapi/ui@latest/dist/cdn/roxy-ui.js"></script>
<roxy-natal-chart id="chart"></roxy-natal-chart>
<script type="module">
  const r = await fetch('/api/natal-chart.php?date=1990-01-15&time=14:30:00&lat=28.6139&lon=77.209&tz=5.5');
  document.getElementById('chart').data = await r.json();
</script>
```

`RoxyApiException` is the only real object on the response path. Three properties matter: `statusCode` (HTTP status as int), `errorCode` (machine-readable, stable, switch on this), and `error` (human-readable, wording may change between releases). Stable codes are `validation_error`, `api_key_required`, `invalid_api_key`, `subscription_inactive`, `not_found`, `rate_limit_exceeded`, and `internal_error`. For unit tests, drop the Saloon `MockClient` in and stub responses by request class without ever touching the network.

```php
use RoxyAPI\Sdk\Generated\Requests\GetDailyHoroscopeRequest;
use Saloon\Http\Faking\MockClient;
use Saloon\Http\Faking\MockResponse;

$roxy = createRoxy('test-key');
$roxy->withMockClient(new MockClient([
    GetDailyHoroscopeRequest::class => MockResponse::make([
        'sign' => 'aries', 'overview' => 'fixture overview',
    ]),
]));
```

## FAQ

**How to add Western astrology to a PHP project?**

Install the SDK with `composer require roxyapi/sdk` and create a client with `$roxy = createRoxy(getenv('ROXY_API_KEY'))`. The astrology namespace exposes 22 endpoints, including `$roxy->astrology->getDailyHoroscope(sign: 'aries')` for a transit-driven daily horoscope and `$roxy->astrology->generateNatalChart(...)` for a full natal chart with planets, houses, and aspects. Every method returns an associative array, so access fields with bracket syntax like `$horoscope['overview']`.

**How to add Vedic astrology and kundli generation to a PHP project?**

After installing `roxyapi/sdk`, call `$roxy->vedicAstrology->generateBirthChart(date: '1990-01-15', time: '14:30:00', latitude: 19.0760, longitude: 72.8777)`. The response carries per-planet nakshatra with name and pada for pada-quarter precision, combustion data, planetary war flags, and per-rashi placements. Pair it with `$roxy->vedicAstrology->getDetailedPanchang(...)` to return 15+ muhurtas (rahuKaal, abhijit, brahma, vijaya, varjyam, amritkalam, and more) in one call.

**How to add numerology to a PHP project?**

Install `roxyapi/sdk` and call `$roxy->numerology->calculateLifePath(year: 1990, month: 1, day: 15)` for the life path number. The numerology namespace also exposes expression, soul urge, personality, personal year, and 36-point relationship compatibility methods. No birth time or coordinates required, pure date arithmetic, and every method accepts an optional `lang` argument for localized interpretations in eight languages.

**How to draw a daily tarot card in PHP?**

Use `$roxy->tarot->getDailyCard(seed: 'user-42')` from the installed `roxyapi/sdk`. Pass a stable seed per user (user id, session token, hashed email) for reproducible daily readings, so same seed plus same date returns the same card every time. Read `$daily['card']['name']` for the card title and `$daily['card']['dailyMessage']` for the interpretation. For multi-card spreads call `$roxy->tarot->castThreeCard(question: '...')` or `$roxy->tarot->castCelticCross(question: '...')`.

**How to geocode a birth city in PHP before generating a chart?**

Call `$roxy->location->searchCities(q: 'Mumbai')` and read the first result from `$cities['cities'][0]`. The response gives `latitude`, `longitude`, and an IANA `timezone` string per city. Feed those three values into every chart endpoint that needs coordinates: natal chart, kundli, panchang, dasha, synastry, transits. The IANA timezone resolves DST correctly for historical birth dates, so a January 1990 New York chart picks EST automatically.

**How to use the RoxyAPI PHP SDK in a Laravel application?**

Register the `RoxyAPI\Sdk\Roxy` connector as a singleton in a service provider: `$this->app->singleton(Roxy::class, fn () => createRoxy(config('services.roxyapi.key')))`. Then inject it into any controller, job, or service via constructor type-hint. The same pattern works in Symfony with `services.yaml`, in Slim through the DI container, in WordPress plugins via the Composer autoload, and in vanilla PHP by constructing the connector once and reusing it across requests.

**How to handle errors from the RoxyAPI PHP SDK?**

Wrap calls in `try { ... } catch (RoxyApiException $e) { ... }` and switch on the machine-readable `$e->errorCode`. Stable codes include `validation_error`, `invalid_api_key`, `subscription_inactive`, `not_found`, `rate_limit_exceeded`, and `internal_error`. The exception also exposes `$e->statusCode` (HTTP status) and `$e->error` (human-readable message, may change wording). Transport failures like timeouts surface with `errorCode` of `connection_error`, so callers only ever catch one exception type.

**How to mock the RoxyAPI PHP SDK in PHPUnit or Pest tests?**

The SDK is built on Saloon, so use the Saloon MockClient to stub responses by request class. Import the request you want to mock (for example `RoxyAPI\Sdk\Generated\Requests\GetDailyHoroscopeRequest`), pass fixture data to `MockResponse::make([...])`, and call `$roxy->withMockClient($mock)`. The mocked call returns the fixture without touching the network, so the same test suite runs in CI without an API key or rate budget.

## Conclusion

The PHP SDK closes the last gap in the RoxyAPI client family: TypeScript, Python, and now PHP share the same operationId-driven surface across 131 endpoints and 12 domains under one key. Install with `composer require roxyapi/sdk`, set `ROXY_API_KEY` in the environment, and ship a Laravel, Symfony, WordPress, or vanilla PHP insight app this afternoon. Start with the [astrology API](/products/astrology-api "production-ready astrology API with natal charts, transits, and synastry") and the [pricing page](/pricing "RoxyAPI pricing and plan tiers") to grab a key.