Skip to content

Commit a852794

Browse files
committed
feat: roxy-sdk Python SDK with codegen pipeline, 10 domains, 120+ endpoints, sync and async
0 parents  commit a852794

18 files changed

Lines changed: 42768 additions & 0 deletions

.github/workflows/release.yml

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
name: Release
2+
3+
on:
4+
# repository_dispatch:
5+
# types: [openapi-updated]
6+
# schedule:
7+
# - cron: '0 6 * * *'
8+
workflow_dispatch:
9+
inputs:
10+
version_bump:
11+
description: 'patch | minor | major'
12+
required: false
13+
default: 'patch'
14+
15+
jobs:
16+
release:
17+
runs-on: ubuntu-latest
18+
environment: pypi
19+
permissions:
20+
contents: write
21+
id-token: write
22+
steps:
23+
- uses: actions/checkout@v5
24+
with:
25+
token: ${{ secrets.GITHUB_TOKEN }}
26+
27+
- uses: actions/setup-python@v5
28+
with:
29+
python-version: '3.12'
30+
31+
- name: Install tools
32+
run: pip install hatch httpx
33+
34+
- name: Fetch latest spec
35+
run: python generate.py
36+
37+
- name: Check if spec changed
38+
id: diff
39+
run: |
40+
if git diff --quiet specs/openapi.json; then
41+
echo "changed=false" >> $GITHUB_OUTPUT
42+
else
43+
echo "changed=true" >> $GITHUB_OUTPUT
44+
fi
45+
46+
- name: Lint and typecheck
47+
if: steps.diff.outputs.changed == 'true' || github.event_name == 'workflow_dispatch'
48+
run: |
49+
pip install ruff mypy
50+
ruff check .
51+
mypy src/roxy_sdk/factory.py src/roxy_sdk/__init__.py
52+
53+
- name: Test
54+
if: steps.diff.outputs.changed == 'true' || github.event_name == 'workflow_dispatch'
55+
run: |
56+
pip install -e . pytest pytest-asyncio
57+
pytest tests/test_factory.py -v
58+
59+
- name: Bump version
60+
if: steps.diff.outputs.changed == 'true' || github.event_name == 'workflow_dispatch'
61+
run: |
62+
python3 -c "
63+
import re
64+
bump = '${{ github.event.inputs.version_bump || 'patch' }}'
65+
path = 'src/roxy_sdk/version.py'
66+
text = open(path).read()
67+
ver = re.search(r'VERSION = \"(.+?)\"', text).group(1)
68+
parts = [int(x) for x in ver.split('.')]
69+
if bump == 'major': parts[0] += 1; parts[1] = 0; parts[2] = 0
70+
elif bump == 'minor': parts[1] += 1; parts[2] = 0
71+
else: parts[2] += 1
72+
new_ver = '.'.join(str(x) for x in parts)
73+
open(path, 'w').write(f'VERSION = \"{new_ver}\"\n')
74+
open('/tmp/new_version.txt', 'w').write(new_ver)
75+
"
76+
77+
- name: Build
78+
if: steps.diff.outputs.changed == 'true' || github.event_name == 'workflow_dispatch'
79+
run: hatch build
80+
81+
- name: Publish to PyPI
82+
if: steps.diff.outputs.changed == 'true' || github.event_name == 'workflow_dispatch'
83+
uses: pypa/gh-action-pypi-publish@release/v1
84+
85+
- name: Commit, tag, push
86+
if: steps.diff.outputs.changed == 'true' || github.event_name == 'workflow_dispatch'
87+
run: |
88+
git config user.name "github-actions[bot]"
89+
git config user.email "github-actions[bot]@users.noreply.github.com"
90+
VERSION=$(cat /tmp/new_version.txt)
91+
git add src/roxy_sdk/version.py specs/openapi.json src/roxy_sdk/factory.py
92+
git commit -m "release: v$VERSION"
93+
git tag "v$VERSION"
94+
git push --follow-tags

.gitignore

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Maintainer-only (not published)
2+
CLAUDE.md
3+
TODO.md
4+
test_import.py
5+
openapi-python-client.toml
6+
7+
# Generated typed models (excluded from wheel, regenerated locally)
8+
src/roxy_sdk/_generated/
9+
10+
# Python
11+
__pycache__/
12+
*.py[cod]
13+
*.pyo
14+
*.pyd
15+
.Python
16+
.venv/
17+
venv/
18+
env/
19+
dist/
20+
build/
21+
*.egg-info/
22+
.eggs/
23+
.pytest_cache/
24+
.mypy_cache/
25+
.ruff_cache/
26+
*.so
27+
28+
# Hatch
29+
.hatch/
30+
31+
# Editor
32+
.DS_Store
33+
.idea/
34+
.vscode/
35+
*.swp
36+
*.swo

AGENTS.md

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
# roxy-sdk (Python) Agent Guide
2+
3+
Python SDK for RoxyAPI. Multi-domain spiritual and metaphysical intelligence API. One API key, 10 domains, sync and async support.
4+
5+
## Install and initialize
6+
7+
```bash
8+
pip install roxy-sdk
9+
```
10+
11+
```python
12+
from roxy_sdk import create_roxy
13+
14+
roxy = create_roxy("your-api-key")
15+
```
16+
17+
`create_roxy` sets the base URL (`https://roxyapi.com/api/v2`) and auth header automatically. Returns a `Roxy` instance with namespaced domain properties.
18+
19+
## Domains
20+
21+
Type `roxy.` to see all available namespaces:
22+
23+
| Namespace | What it covers |
24+
|-----------|----------------|
25+
| `roxy.astrology` | Western astrology: natal charts, horoscopes, synastry, moon phases, transits, compatibility |
26+
| `roxy.vedic_astrology` | Vedic/Jyotish: birth charts, dashas, nakshatras, panchang, KP system, doshas, yogas |
27+
| `roxy.tarot` | Rider-Waite-Smith deck: spreads, daily pulls, yes/no, Celtic Cross, custom layouts |
28+
| `roxy.numerology` | Life path, expression, soul urge, personal year, karmic analysis, compatibility |
29+
| `roxy.crystals` | Crystal healing properties, zodiac/chakra pairings, birthstones, search |
30+
| `roxy.iching` | I Ching: hexagrams, trigrams, coin casting, daily readings |
31+
| `roxy.angel_numbers` | Angel number meanings, pattern analysis, daily guidance |
32+
| `roxy.dreams` | Dream symbol dictionary and interpretations |
33+
| `roxy.location` | City geocoding for birth chart coordinates |
34+
| `roxy.usage` | API usage stats and subscription info |
35+
36+
## Critical patterns
37+
38+
### Sync calls (default)
39+
40+
```python
41+
horoscope = roxy.astrology.get_daily_horoscope(sign="aries")
42+
card = roxy.tarot.draw_cards(count=3)
43+
life_path = roxy.numerology.calculate_life_path(year=1990, month=1, day=15)
44+
```
45+
46+
### Async calls (append _async)
47+
48+
Every sync method has an async variant with `_async` suffix:
49+
50+
```python
51+
horoscope = await roxy.astrology.get_daily_horoscope_async(sign="aries")
52+
card = await roxy.tarot.draw_cards_async(count=3)
53+
```
54+
55+
### POST endpoints (charts, spreads, calculations)
56+
57+
Most chart and calculation endpoints require date, time, and coordinates:
58+
59+
```python
60+
chart = roxy.astrology.generate_natal_chart(
61+
date="1990-01-15",
62+
time="14:30:00",
63+
latitude=28.6139,
64+
longitude=77.209,
65+
)
66+
67+
vedic = roxy.vedic_astrology.generate_birth_chart(
68+
date="1990-01-15",
69+
time="14:30:00",
70+
latitude=28.6139,
71+
longitude=77.209,
72+
)
73+
74+
celtic = roxy.tarot.cast_celtic_cross(question="What should I focus on?")
75+
76+
numerology = roxy.numerology.generate_numerology_chart(
77+
full_name="John Doe",
78+
year=1990,
79+
month=1,
80+
day=15,
81+
)
82+
```
83+
84+
### Error handling
85+
86+
Errors raise `RoxyAPIError` with `error` (message), `code` (machine-readable), and `status_code` attributes:
87+
88+
```python
89+
from roxy_sdk import create_roxy, RoxyAPIError
90+
91+
try:
92+
result = roxy.astrology.get_daily_horoscope(sign="invalid")
93+
except RoxyAPIError as e:
94+
print(e.code) # "validation_error"
95+
print(e.error) # "Invalid sign"
96+
print(e.status_code) # 400
97+
```
98+
99+
Error codes: `validation_error`, `api_key_required`, `invalid_api_key`, `subscription_not_found`, `subscription_inactive`, `not_found`, `rate_limit_exceeded`, `internal_error`.
100+
101+
## Common tasks
102+
103+
| Task | Code |
104+
|------|------|
105+
| Daily horoscope | `roxy.astrology.get_daily_horoscope(sign="aries")` |
106+
| Birth chart (Western) | `roxy.astrology.generate_natal_chart(date, time, latitude, longitude)` |
107+
| Birth chart (Vedic) | `roxy.vedic_astrology.generate_birth_chart(date, time, latitude, longitude)` |
108+
| Compatibility score | `roxy.astrology.calculate_compatibility(person1, person2)` |
109+
| Tarot daily card | `roxy.tarot.get_daily_card()` |
110+
| Celtic Cross reading | `roxy.tarot.cast_celtic_cross(question="...")` |
111+
| Draw tarot cards | `roxy.tarot.draw_cards(count=3)` |
112+
| Life Path number | `roxy.numerology.calculate_life_path(year, month, day)` |
113+
| Full numerology chart | `roxy.numerology.generate_numerology_chart(full_name=, year=, month=, day=)` |
114+
| Crystal by zodiac | `roxy.crystals.get_crystals_by_zodiac(sign="aries")` |
115+
| Crystal search | `roxy.crystals.search_crystals(q="amethyst")` |
116+
| I Ching reading | `roxy.iching.cast_reading()` |
117+
| Angel number meaning | `roxy.angel_numbers.get_angel_number(number="1111")` |
118+
| Dream symbol lookup | `roxy.dreams.get_dream_symbol(id="flying")` |
119+
| Find city coordinates | `roxy.location.search_cities(q="Mumbai")` |
120+
| Check API usage | `roxy.usage.get_usage_stats()` |
121+
122+
## Location helper
123+
124+
Most chart endpoints need `latitude` and `longitude`. Use the location API to geocode:
125+
126+
```python
127+
result = roxy.location.search_cities(q="Mumbai, India")
128+
city = result["cities"][0]
129+
# Use city["latitude"] and city["longitude"] in chart requests
130+
```
131+
132+
## Gotchas
133+
134+
- **All parameters are keyword arguments.** Use `sign="aries"` not positional `"aries"`.
135+
- **Async methods end with `_async`.** Every sync method has a matching async variant.
136+
- **Do not expose API keys client-side.** Call Roxy from server code only.
137+
- **Chart endpoints need coordinates.** Use `roxy.location.search_cities()` to get lat/lng.
138+
- **Date format is `YYYY-MM-DD`, time is `HH:MM:SS`.** Both are strings.
139+
- **Errors raise `RoxyAPIError`.** Catch it and check `e.code`, `e.error`, and `e.status_code`.
140+
- **Switch on `code`, not `error`.** The `code` field is stable. The `error` message may change.
141+
142+
## Links
143+
144+
- Interactive API docs: https://roxyapi.com/api-reference
145+
- Pricing and API keys: https://roxyapi.com/pricing
146+
- MCP for AI agents: https://roxyapi.com/docs/mcp
147+
- TypeScript SDK: https://www.npmjs.com/package/@roxyapi/sdk

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 RoxyAPI
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

0 commit comments

Comments
 (0)