- Docs
- Build With Roxy
- SDK (TypeScript / Python / PHP)
SDK (TypeScript / Python / PHP / WordPress)
Official Roxy SDKs for TypeScript, Python, and PHP, plus a WordPress plugin with Gutenberg blocks and shortcodes. Full type safety and IDE autocomplete on every code SDK, drop-in shortcodes on WordPress, all hitting the same 145+ endpoints across 12 domains. Same API shape, same domain names, three languages. Drop a composer require, pip install, or npm install into any Laravel, Symfony, Slim, Django, FastAPI, Next.js, or Express project and ship a natal-chart endpoint in five minutes.
- TypeScript:
@roxyapi/sdkon npm - Python:
roxy-sdkon PyPI - PHP:
roxyapi/sdkon Packagist (PHP 8.2+) - WordPress: RoxyAPI plugin on the WordPress.org Plugin Directory
- UI components:
@roxyapi/uiand@roxyapi/ui-reacton npm. Open-source web components for charts, tables, cards, and forms across every domain. Setup walkthrough at /docs/ui (Next.js, vanilla HTML, shadcn). Catalog and live customizer at /ui.
Install
npm install @roxyapi/sdk
bun add @roxyapi/sdk
pnpm add @roxyapi/sdk
yarn add @roxyapi/sdk
pip install roxy-sdk
uv add roxy-sdk
poetry add roxy-sdk
composer require roxyapi/sdk
In WordPress admin: Plugins → Add New → search RoxyAPI → Install Now → Activate. Settings → RoxyAPI to paste your API key. Full integration guide at /docs/integrations/wordpress. Prefer the latest unreleased code? Grab roxyapi.zip from GitHub Releases and upload via Plugins → Add New → Upload Plugin.
Quick start
Two lines to instantiate, one line per API call. createRoxy / create_roxy / RoxyAPI\Sdk\createRoxy set the base URL, auth header, and SDK identification header automatically.
import { createRoxy } from '@roxyapi/sdk';
const roxy = createRoxy(process.env.ROXY_API_KEY!);
// Daily horoscope
const { data } = await roxy.astrology.getDailyHoroscope({
path: { sign: 'aries' },
});
// Numerology life path
const { data: lp } = await roxy.numerology.calculateLifePath({
body: { year: 1990, month: 1, day: 15 },
});
// Tarot Celtic Cross spread
const { data: reading } = await roxy.tarot.castCelticCross({
body: { question: 'What should I focus on this month?' },
});
from roxy_sdk import create_roxy
roxy = create_roxy("your-api-key")
# Daily horoscope
horoscope = roxy.astrology.get_daily_horoscope(sign="aries")
# Numerology life path
lp = roxy.numerology.calculate_life_path(year=1990, month=1, day=15)
# Tarot Celtic Cross spread
reading = roxy.tarot.cast_celtic_cross(question="What should I focus on this month?")
<?php
use function RoxyAPI\Sdk\createRoxy;
$roxy = createRoxy(getenv('ROXY_API_KEY'));
// Daily horoscope
$horoscope = $roxy->astrology->getDailyHoroscope(sign: 'aries');
// Numerology life path
$lp = $roxy->numerology->calculateLifePath(year: 1990, month: 1, day: 15);
// Tarot Celtic Cross spread
$reading = $roxy->tarot->castCelticCross(question: 'What should I focus on this month?');
Never expose your API key in client-side code. Call Roxy from your server, API routes, serverless functions, or background workers only.
Authentication
Pass your API key on initialization. Get your API key at roxyapi.com/pricing, delivered instantly after checkout.
import { createRoxy } from '@roxyapi/sdk';
const roxy = createRoxy(process.env.ROXY_API_KEY!);
import os
from roxy_sdk import create_roxy
roxy = create_roxy(os.environ["ROXY_API_KEY"])
<?php
use function RoxyAPI\Sdk\createRoxy;
$roxy = createRoxy(getenv('ROXY_API_KEY'));
Domains
Each domain is a namespace on the roxy instance. TypeScript returns typed objects via { data, error, response } per call. Python and PHP return the decoded JSON directly as associative arrays / dicts. Python raises RoxyAPIError on failure; PHP throws RoxyApiException (catch it and switch on $e->errorCode).
| Namespace (TS / PHP) | Namespace (Python) | What it covers |
|---|---|---|
roxy.astrology / $roxy->astrology | roxy.astrology | Western astrology: natal charts, horoscopes, synastry, transits, moon phases |
roxy.vedicAstrology / $roxy->vedicAstrology | roxy.vedic_astrology | Vedic / Jyotish: kundli, panchang, dashas, nakshatras, doshas, KP system |
roxy.numerology / $roxy->numerology | roxy.numerology | Life path, expression, soul urge, personal year, karmic lessons |
roxy.tarot / $roxy->tarot | roxy.tarot | Daily card, custom draws, three-card, Celtic Cross, yes / no, love spread |
roxy.biorhythm / $roxy->biorhythm | roxy.biorhythm | Daily check-in, multi-day forecast, critical days, compatibility |
roxy.iching / $roxy->iching | roxy.iching | Daily hexagram, three-coin cast, 64 hexagrams, trigrams |
roxy.crystals / $roxy->crystals | roxy.crystals | Crystal meanings, zodiac / chakra pairings, birthstone, search |
roxy.dreams / $roxy->dreams | roxy.dreams | Dream symbol dictionary, interpretations |
roxy.angelNumbers / $roxy->angelNumbers | roxy.angel_numbers | Number meanings, universal digit-root lookup, daily |
roxy.location / $roxy->location | roxy.location | City search for birth chart coordinates |
roxy.usage / $roxy->usage | roxy.usage | API usage stats, remaining quota, subscription info |
Location first
Every chart, horoscope, panchang, dasha, dosha, navamsa, KP, synastry, compatibility, and natal endpoint needs latitude, longitude, and a timezone. Call the location API first, then feed the result into the chart method.
The location response is a pagination envelope. Each city has both an IANA timezone string and a decimal utcOffset. Either form works on chart endpoints — pass the IANA string for DST-correct historical charts, or the utcOffset decimal if you prefer numbers.
const { data } = await roxy.location.searchCities({
query: { q: 'Mumbai, India' },
});
// Response: { total, limit, offset, cities: [...] }
const { latitude, longitude, timezone } = data.cities[0];
const { data: chart } = await roxy.vedicAstrology.generateBirthChart({
body: {
date: '1990-01-15',
time: '14:30:00',
latitude,
longitude,
timezone, // IANA string like "Asia/Kolkata" — server resolves DST for the chart date
},
});
result = roxy.location.search_cities(q="Mumbai, India")
# Response: { "total", "limit", "offset", "cities": [...] }
city = result["cities"][0]
chart = roxy.vedic_astrology.generate_birth_chart(
date="1990-01-15", time="14:30:00",
latitude=city["latitude"], longitude=city["longitude"],
timezone=city["timezone"], # IANA string; server resolves DST for the chart date
)
$result = $roxy->location->searchCities(q: 'Mumbai, India');
// Response carries total, limit, offset, cities
$city = $result['cities'][0];
$chart = $roxy->vedicAstrology->generateBirthChart(
date: '1990-01-15',
time: '14:30:00',
latitude: $city['latitude'],
longitude: $city['longitude'],
timezone: $city['timezone'], // IANA string; server resolves DST for the chart date
);
Chart endpoints accept timezone as either a decimal number (5.5 for IST, -5 for EST, 9 for Tokyo) or an IANA identifier ("Asia/Kolkata", "America/New_York"). IANA strings are resolved server-side to the DST-correct offset for the request date, so a January 1990 New York birth gets EST (-5) even when you geocoded the city in July. The utcOffset field on the Location response is a convenience decimal if you prefer numbers. Both forms produce identical charts.
Examples
Daily horoscope
const { data, error } = await roxy.astrology.getDailyHoroscope({
path: { sign: 'scorpio' },
});
if (error) {
console.error(error);
} else {
console.log(data.overview); // General daily forecast
console.log(data.love); // Love and relationship forecast
console.log(data.career); // Career outlook
}
horoscope = roxy.astrology.get_daily_horoscope(sign="scorpio")
print(horoscope["overview"]) # General daily forecast
print(horoscope["love"]) # Love and relationship forecast
print(horoscope["career"]) # Career outlook
$horoscope = $roxy->astrology->getDailyHoroscope(sign: 'scorpio');
echo $horoscope['overview']; // General daily forecast
echo $horoscope['love']; // Love and relationship forecast
echo $horoscope['career']; // Career outlook
Numerology life path
const { data } = await roxy.numerology.calculateLifePath({
body: { year: 1990, month: 1, day: 15 },
});
console.log(data.number); // e.g. 7
console.log(data.type); // "single" | "master"
result = roxy.numerology.calculate_life_path(year=1990, month=1, day=15)
print(result["number"]) # e.g. 7
print(result["type"]) # "single" | "master"
$result = $roxy->numerology->calculateLifePath(year: 1990, month: 1, day: 15);
echo $result['number']; // e.g. 7
echo $result['type']; // "single" | "master"
Vedic birth chart
The response groups planets by the rashi (sign) they occupy. Each rashi has a signs[] array (planets in that rashi, often empty) plus a top-level meta dict with every planet keyed by name.
const { data } = await roxy.vedicAstrology.generateBirthChart({
body: {
date: '1990-01-15',
time: '14:30:00',
latitude: 28.6139,
longitude: 77.209,
timezone: 5.5,
},
});
// Iterate rashis (aries..pisces) for the 12-sign chart
for (const rashi of ['aries', 'taurus', 'gemini'] as const) {
console.log(rashi, data[rashi].signs); // planets in this rashi
}
// Or look up any planet directly
console.log(data.meta.Sun.rashi); // "Capricorn"
console.log(data.meta.Moon.nakshatra.name); // nakshatra name
chart = roxy.vedic_astrology.generate_birth_chart(
date="1990-01-15", time="14:30:00",
latitude=28.6139, longitude=77.209, timezone="Asia/Kolkata",
)
# Iterate rashis for the 12-sign chart
for rashi in ["aries", "taurus", "gemini"]:
print(rashi, chart[rashi]["signs"])
# Or look up any planet directly
print(chart["meta"]["Sun"]["rashi"]) # "Capricorn"
print(chart["meta"]["Moon"]["nakshatra"]["name"]) # nakshatra name
$chart = $roxy->vedicAstrology->generateBirthChart(
date: '1990-01-15',
time: '14:30:00',
latitude: 28.6139,
longitude: 77.209,
timezone: 5.5,
);
// Iterate rashis for the 12-sign chart
foreach (['aries', 'taurus', 'gemini'] as $rashi) {
echo $rashi, count($chart[$rashi]['signs']); // planets in this rashi
}
// Or look up any planet directly
echo $chart['meta']['Sun']['rashi']; // "Capricorn"
echo $chart['meta']['Moon']['nakshatra']['name']; // nakshatra name
Western natal chart
const { data } = await roxy.astrology.generateNatalChart({
body: {
date: '1990-01-15',
time: '14:30:00',
latitude: 28.6139,
longitude: 77.209,
timezone: 5.5,
},
});
console.log(data.planets.length); // 13 (incl. lunar nodes and Chiron)
console.log(data.houses.length); // 12
console.log(data.ascendant.sign); // ascendant zodiac sign
console.log(data.midheaven.sign); // midheaven zodiac sign
natal = roxy.astrology.generate_natal_chart(
date="1990-01-15", time="14:30:00",
latitude=28.6139, longitude=77.209, timezone="Asia/Kolkata",
)
print(len(natal["planets"])) # 13
print(len(natal["houses"])) # 12
print(natal["ascendant"]["sign"]) # ascendant zodiac sign
print(natal["midheaven"]["sign"]) # midheaven zodiac sign
$natal = $roxy->astrology->generateNatalChart(
date: '1990-01-15',
time: '14:30:00',
latitude: 28.6139,
longitude: 77.209,
timezone: 5.5,
);
echo count($natal['planets']); // 13
echo count($natal['houses']); // 12
echo $natal['ascendant']['sign']; // ascendant zodiac sign
echo $natal['midheaven']['sign']; // midheaven zodiac sign
Tarot daily card
const { data } = await roxy.tarot.getDailyCard({ body: { seed: 'user-123' } });
console.log(data.card.name); // e.g. "The Star"
console.log(data.dailyMessage); // concise daily guidance
console.log(data.card.meaning); // full card interpretation
card = roxy.tarot.get_daily_card(seed="user-123")
print(card["card"]["name"]) # e.g. "The Star"
print(card["dailyMessage"]) # concise daily guidance
print(card["card"]["meaning"]) # full card interpretation
$card = $roxy->tarot->getDailyCard(seed: 'user-123');
echo $card['card']['name']; // e.g. "The Star"
echo $card['dailyMessage']; // concise daily guidance
echo $card['card']['meaning']; // full card interpretation
Angel number lookup
const { data } = await roxy.angelNumbers.getAngelNumber({
path: { number: '1111' },
});
console.log(data.coreMessage); // Short divine message summary
console.log(data.meaning.spiritual); // Spiritual interpretation
console.log(data.meaning.love); // Love / relationship meaning
result = roxy.angel_numbers.get_angel_number(number="1111")
print(result["coreMessage"]) # Short divine message summary
print(result["meaning"]["spiritual"]) # Spiritual interpretation
print(result["meaning"]["love"]) # Love / relationship meaning
$result = $roxy->angelNumbers->getAngelNumber(number: '1111');
echo $result['coreMessage']; // Short divine message summary
echo $result['meaning']['spiritual']; // Spiritual interpretation
echo $result['meaning']['love']; // Love / relationship meaning
Check usage
const { data } = await roxy.usage.getUsageStats();
console.log(`${data.usedThisMonth} / ${data.requestsPerMonth} requests used`);
stats = roxy.usage.get_usage_stats()
print(f"{stats['usedThisMonth']} / {stats['requestsPerMonth']} requests used")
$stats = $roxy->usage->getUsageStats();
echo "{$stats['usedThisMonth']} / {$stats['requestsPerMonth']} requests used";
Multi-language responses
Interpretations are available in eight languages: English (en), Turkish (tr), German (de), Spanish (es), French (fr), Hindi (hi), Portuguese (pt), Russian (ru).
const { data } = await roxy.tarot.getDailyCard({
body: { date: '2026-04-22' },
query: { lang: 'es' },
});
card = roxy.tarot.get_daily_card(date="2026-04-22", lang="es")
$card = $roxy->tarot->getDailyCard(date: '2026-04-22', lang: 'es');
Supported: astrology, vedicAstrology / vedic_astrology, numerology, tarot, biorhythm, iching, crystals, angelNumbers / angel_numbers. English-only: dreams, location, usage.
Async support
TypeScript is async by default (every method returns a Promise). Python ships an _async variant for every sync method, for asyncio, FastAPI, or any event loop. PHP is synchronous per call; for concurrent fan-out (e.g. fetching 12 horoscopes in parallel) use the Saloon connector's request pool — see the PHP SDK README for examples.
// Already async — every method returns a Promise
const { data } = await roxy.astrology.getDailyHoroscope({ path: { sign: 'aries' } });
import asyncio
from roxy_sdk import create_roxy
async def main():
roxy = create_roxy("your-api-key")
horoscope = await roxy.astrology.get_daily_horoscope_async(sign="aries")
card = await roxy.tarot.get_daily_card_async()
print(horoscope, card)
asyncio.run(main())
// Each call is synchronous. For concurrent fan-out, use the Saloon pool API
// on the underlying connector (Saloon ships a battle-tested request pool).
$horoscope = $roxy->astrology->getDailyHoroscope(sign: 'aries');
$card = $roxy->tarot->getDailyCard();
Error handling
TypeScript returns { data, error, response } per call. Python raises RoxyAPIError. PHP throws RoxyApiException. All three expose a stable code / errorCode field you can branch on.
const { data, error } = await roxy.tarot.castYesNo({
body: { question: 'Should I take this opportunity?' },
});
if (error) {
switch (error.code) {
case 'validation_error':
console.error('Bad input:', error.error);
break;
case 'rate_limit_exceeded':
console.error('Monthly quota reached');
break;
default:
console.error('API error:', error.code, error.error);
}
} else {
console.log(data.answer); // "Yes" | "No" | "Maybe"
}
from roxy_sdk import create_roxy, RoxyAPIError
try:
result = roxy.tarot.cast_yes_no(question="Should I take this opportunity?")
print(result["answer"]) # "Yes" | "No" | "Maybe"
except RoxyAPIError as e:
if e.code == "validation_error":
print(f"Bad input: {e.error}")
elif e.code == "rate_limit_exceeded":
print("Monthly quota reached")
else:
print(f"API error: {e.code} {e.error}")
use RoxyAPI\Sdk\RoxyApiException;
try {
$result = $roxy->tarot->castYesNo(question: 'Should I take this opportunity?');
echo $result['answer']; // "Yes" | "No" | "Maybe"
} catch (RoxyApiException $e) {
match ($e->errorCode) {
'validation_error' => fwrite(STDERR, "Bad input: {$e->error}\n"),
'rate_limit_exceeded' => fwrite(STDERR, "Monthly quota reached\n"),
default => fwrite(STDERR, "API error: {$e->errorCode} {$e->error}\n"),
};
}
Error codes
| Status | Code | When |
|---|---|---|
| 400 | validation_error | Missing or invalid parameters. Check issues[] for per-field failures. |
| 401 | api_key_required | No API key provided |
| 401 | invalid_api_key | Key format invalid or tampered |
| 401 | subscription_not_found | Key references non-existent subscription |
| 401 | subscription_inactive | Subscription cancelled, expired, or suspended |
| 404 | not_found | Resource does not exist |
| 429 | rate_limit_exceeded | Monthly request quota reached |
| 500 | internal_error | Server error |
The code field is machine-readable and stable, safe to switch on. The error field is human-readable and may change wording.
Type safety
Every SDK is fully typed for its language. TypeScript ships generated .d.ts definitions. PHP ships PHPDoc on every Saloon Request class plus a phpstan-level-8-clean public surface. Python ships py.typed for mypy and Pyright.
// TypeScript knows sign must be one of the 12 zodiac signs
const { data } = await roxy.astrology.getDailyHoroscope({
path: { sign: 'aries' }, // autocompletes all 12 options
});
// data is typed, no manual casting needed
console.log(data.date); // string
console.log(data.overview); // string
You can also import individual namespace classes or response types:
import { Astrology, type GetAstrologyHoroscopeBySignDailyResponse } from '@roxyapi/sdk';
PHP uses named arguments (PHP 8.0+) for parameters and PHPDoc-typed Saloon Request classes for response shapes. PhpStorm, VS Code (Intelephense), and phpstan all see the full signature without any extra setup.
Gotchas
Parameters are structured
TypeScript always uses { path: {...} }, { body: {...} }, or { query: {...} }. Python uses keyword arguments only (sign="aries"), never positional. PHP uses named arguments (sign: 'aries'), never positional. Do not mix the patterns.
Timezone accepts both IANA and decimal
Chart endpoints accept timezone as either a decimal (5.5, -5, 0) or an IANA identifier ("Asia/Kolkata", "America/New_York"). IANA is preferred because it is DST-resolved against the request's date, so historical birth charts pick the correct offset even when you geocoded the city today. Both city.timezone and city.utcOffset from the Location response work.
Location returns an envelope, not a bare array
data.cities[0] in TypeScript and result["cities"][0] in Python. The top-level object carries total, limit, offset for pagination. Same envelope pattern applies to tarot.listCards (data.cards), iching.listHexagrams (data.hexagrams), dreams.searchDreamSymbols (data.symbols), and crystals.searchCrystals / getCrystalsByZodiac / getCrystalsByChakra (data.crystals).
Date format is YYYY-MM-DD, time is HH:MM:SS
Both are strings. Time must include seconds, 14:30 will be rejected.
Do not guess method names
Type roxy.domain. and let autocomplete show methods. Names come from operationId in the OpenAPI spec, not URL paths. Examples: getDailyHoroscope (not dailyHoroscope), calculateLifePath (not lifePath), castCelticCross (not celticCross).
Chart endpoints need coordinates
Use the location API to geocode cities before any birth chart, synastry, panchang, KP, or natal method. Never hardcode a user's latitude, longitude, or timezone from memory.
Do not expose API keys client-side
Call Roxy from server code, API routes, serverless functions, or background workers only. Any key shipped to the browser is a leaked key.
Do not use raw fetch or requests
The SDK handles auth headers, base URL, SDK identification, and typed responses. Raw HTTP clients re-invent this and miss the type safety.
Python errors raise RoxyAPIError, PHP throws RoxyApiException
Catch and switch on e.code (Python) or $e->errorCode (PHP), not the human-readable message text. The codes are stable between releases; the message text may change.
TypeScript data and error are mutually exclusive
If error is set, data is undefined. Always check error first.
Render the response in the browser
For projects that need to display the response visually (charts, tables, cards, forms) without writing your own SVG geometry or table layouts, install Roxy UI alongside the SDK.
npm install @roxyapi/ui @roxyapi/sdk
bun add @roxyapi/ui @roxyapi/sdk
<script src="https://cdn.jsdelivr.net/npm/@roxyapi/ui@latest/dist/cdn/roxy-ui.js"></script>
Components are stateless. Caller fetches via the SDK, passes the response as the data prop. Theming via CSS custom properties on :root or per element. Works in React, Next.js, Vue, Svelte, Angular, vanilla HTML, and WordPress.
'use client';
import { createRoxy } from '@roxyapi/sdk';
import { RoxyNatalChart, RoxyLocationSearch } from '@roxyapi/ui-react';
import { useState } from 'react';
const roxy = createRoxy(process.env.NEXT_PUBLIC_ROXY_API_KEY!);
export default function Page() {
const [chart, setChart] = useState(null);
const onLocationSelect = async (e: CustomEvent<{ latitude: number; longitude: number; timezone: string }>) => {
const { data } = await roxy.astrology.generateNatalChart({
body: { date: '1990-01-15', time: '14:30:00', ...e.detail },
});
setChart(data);
};
return (
<>
<RoxyLocationSearch onroxy-location-select={onLocationSelect} />
{chart && <RoxyNatalChart data={chart} />}
</>
);
}
<script 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">
import { createRoxy } from 'https://cdn.jsdelivr.net/npm/@roxyapi/sdk@1/dist/factory.js';
const roxy = createRoxy(import.meta.env?.ROXY_API_KEY);
const { data } = await roxy.astrology.generateNatalChart({
body: { date: '1990-01-15', time: '14:30:00', latitude: 28.6139, longitude: 77.2090, timezone: 5.5 },
});
document.getElementById('chart').data = data;
</script>
add_action('wp_enqueue_scripts', function () {
wp_enqueue_script(
'roxy-ui',
'https://cdn.jsdelivr.net/npm/@roxyapi/ui@latest/dist/cdn/roxy-ui.js',
[], null, true
);
});
// In a template or shortcode handler:
echo '<roxy-natal-chart data="' . esc_attr(wp_json_encode($response)) . '"></roxy-natal-chart>';
Full setup walkthrough at /docs/ui, catalog and live customizer at /ui. Source on GitHub at RoxyAPI/ui, MIT licensed, published with SLSA provenance via OIDC.
AI coding agents
All three SDKs ship AGENTS.md bundled in the package so AI agents (Claude Code, Cursor, GitHub Copilot, OpenAI Codex, Gemini CLI) read it directly from node_modules/@roxyapi/sdk/AGENTS.md, the installed Python package, or vendor/roxyapi/sdk/AGENTS.md.
- Quickstart, critical patterns, common tasks reference, gotchas
- Field format table covering timezone decimals, date / time strings, nested person objects, enum values
- MCP tool name mapping for every REST endpoint
For agents in projects WITHOUT any SDK installed (Go, Ruby, Rust, raw curl, Bash), there is also a site-level AGENTS.md playbook at https://roxyapi.com/AGENTS.md covering the same Rule 0, common tasks, body shapes, error contract, and field gotchas, but language-agnostic.
Also available: a remote MCP server per domain at https://roxyapi.com/mcp/{domain} (Streamable HTTP, no stdio / no self-hosting) for agents that speak the Model Context Protocol.
Links
- API Reference — browse all endpoints and try live calls
- Quickstart — your first API call in 60 seconds
- MCP Setup — connect AI agents to Roxy
- Starter Apps — full app templates to clone
- Pricing — get your API key
- Roxy UI setup walkthrough — Next.js, vanilla HTML, shadcn, theming, gotchas
- Roxy UI catalog — every component with live preview and customizer
- TypeScript SDK on GitHub
- Python SDK on GitHub
- PHP SDK on GitHub
- WordPress plugin on wordpress.org (source on GitHub)
- Roxy UI on GitHub