Skip to content

Latest commit

 

History

History
393 lines (324 loc) · 32.5 KB

AGENTS.md

File metadata and controls

393 lines (324 loc) · 32.5 KB

roxy-sdk (Python) - Agent Guide

Python SDK for RoxyAPI. 18+ domains (Western astrology, Vedic astrology, forecast, human design, Chinese astrology, feng shui, Mesoamerican astrology, Vastu, numerology, Kabbalah, tarot, biorhythm, Ayurveda, I Ching, crystals, dreams, angel numbers, location) plus utility namespaces (usage, languages). One API key, sync and async.

Install and initialize

pip install roxy-sdk
from roxy_sdk import create_roxy

# Retries 429, 500, 502, 503 and 504 by default. Optional settings, shown with their defaults:
# create_roxy(key, timeout=30.0, max_retries=2, initial_delay=0.5, max_delay=30.0)
roxy = create_roxy("your-api-key")

create_roxy sets the base URL (https://roxyapi.com/api/v2) and auth header automatically. Returns a Roxy instance with namespaced domain properties.

Critical rule: geocode before any chart endpoint

Every chart, horoscope, panchang, dasha, dosha, navamsa, KP, synastry, compatibility, and natal endpoint needs latitude, longitude, and (for Western) timezone. Never ask the user for coordinates. Always call roxy.location.search_cities first.

result = roxy.location.search_cities(q="New York")
city = result["cities"][0]
lat, lng, tz = city["latitude"], city["longitude"], city["timezone"]
# `timezone` is the IANA string ("America/New_York"). Pass it directly to any chart endpoint.
# The server resolves it to the DST-correct decimal offset using the date of the chart itself,
# so a January 1990 New York chart gets EST (-5) even when you looked the city up in July.
# city["utcOffset"] is the offset in force today, not on the birth date, so pass the IANA `timezone` string.

q accepts bare city ("Paris"), city + country ("Berlin Germany"), or comma-qualified ("Springfield, Illinois"). Use the qualified form to disambiguate same-named cities.

Domains

Type roxy. to see all available namespaces. Type roxy.{domain}. in an IDE with a Python LSP to see every method.

Namespace Methods What it covers
roxy.astrology 39 Western astrology API for natal birth charts, daily, weekly, monthly, and yearly horoscopes with unique content per s...
roxy.vedic_astrology 58 Vedic astrology (Jyotish) and KP API for kundli generation with the sixteen Shodasavarga divisional charts (D1 to D60...
roxy.forecast 5 Astrology forecast API that merges upcoming transit aspects, sign ingresses, retrograde stations, new and full moons,...
roxy.human_design 12 Human Design API that generates the full bodygraph from a birth moment: type, strategy, inner authority, profile, def...
roxy.chinese_astrology 16 Chinese zodiac and BaZi astrology API: Four Pillars charts, Chinese zodiac signs and the Chinese lunisolar calendar f...
roxy.feng_shui 11 Compute classical feng shui from one API: Xuan Kong flying star natal charts for any of the nine periods and 24 mount...
roxy.mesoamerican_astrology 18 Calculate Mayan astrology day signs, the Tzolkin sacred round, the Haab year, the full Long Count and the Aztec tonal...
roxy.vastu 10 Vastu Shastra API for directional home and plot analysis: entrance padas with the classical effect of each of the 32...
roxy.numerology 20 Numerology API for life path numbers, complete numerology charts and compatibility, in both Pythagorean and Chaldean...
roxy.kabbalah 12 Kabbalah API for gematria, the 72 names, the Tree of Life and the Hebrew birthday
roxy.tarot 10 Tarot reading API with the complete 78-card Rider-Waite-Smith deck and card meanings for love, career, health, and sp...
roxy.biorhythm 6 Biorhythm API for entertainment and reflection, with 10 model cycle types across 3 primary (physical, emotional, inte...
roxy.ayurveda 8 Ayurveda API for dosha profiles, the dinacharya daily routine and the ritucharya seasonal regimen, with a verse cited...
roxy.iching 9 I-Ching oracle API with all 64 hexagrams, 384 changing lines, 8 trigrams, and modern interpretations for love, career...
roxy.crystals 12 Crystal healing API covering the most popular and widely-searched healing crystals and gemstones, from Amethyst and R...
roxy.dreams 5 Dream interpretation API with a 2,200+ symbol dream dictionary and psychological meanings covering animals, objects,...
roxy.angel_numbers 4 Angel numbers API with meanings for 111, 222, 333, 444, 555, 666, 777, 888, 999, 1111, and 75+ sequences covering eve...
roxy.location 3 Timezone and location API with city search and geocoding across 5,180,000+ cities, towns and villages in 240+ countri...
roxy.usage 1 Monitor your API usage, check rate limits, and track request consumption
roxy.languages 2 List the response languages accepted by the lang query parameter on every i18n-aware endpoint

Quality guidelines for agents

The rules to follow when writing any call with this SDK. Get these right and the generated signatures do the rest.

  • Responses are dicts. Every method returns dict[str, Any]. Access fields with result["key"]["subkey"], never result.key.subkey (Python will raise AttributeError: 'dict' object has no attribute ...).
  • Method names are snake_case versions of the OpenAPI operationId (e.g. castThreeCard -> cast_three_card, analyzeNumberSequence -> analyze_number_sequence). Every sync method has an _async variant; use await with the async variants.
  • Param names are snake_case versions of the spec param names (fullName -> full_name, birthDate -> birth_date, houseSystem -> house_system). All params are keyword-only.
  • When in doubt about a method or kwarg, read the generated signatures. Check roxy_sdk.factory directly or run python -c "from roxy_sdk import Roxy; help(Roxy)" - the generated signatures are the contract.
  • Response field names come from the response schema of the spec. They match it exactly. Never invent or pluralize. If a field is not in the spec, it is not in the response.
  • Look up any operation or field beyond this guide. Query the combined OpenAPI spec at https://roxyapi.com/api/v2/openapi.json with the jq recipe in https://roxyapi.com/AGENTS.md, or search the keyless Docs MCP server at https://roxyapi.com/mcp/docs (one tool, search_docs).
  • Strings everywhere. date is "YYYY-MM-DD", time is "HH:MM:SS", timezone is an IANA name ("Asia/Kolkata", "America/New_York") - the server resolves DST for the chart date. number (angel) is "1111", month (birthstone) is "1", number (hexagram) is "1". Numeric kwargs are only latitude, longitude, year, month (numerology), day, count (tarot draw).
  • Nested dicts accept any value type. Inside person1 / person2 dicts any value type works because the kwarg is typed dict[str, Any]; only the top-level timezone kwarg needs string form.
  • Do not hand-roll requests. No raw HTTP calls. The SDK injects auth, the base URL and the error type; it retries 429, 500, 502, 503 and 504 up to twice by default (see Retries; create_roxy(key, max_retries=0) turns that off).

Critical patterns

Two-step pattern for coordinate-dependent endpoints

result = roxy.location.search_cities(q="London")
city = result["cities"][0]

chart = roxy.astrology.generate_natal_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 date
)

One lookup feeds every domain. The same birth dict, spread with **birth, is the kwargs for astrology.generate_natal_chart, vedic_astrology.generate_birth_chart, vedic_astrology.get_current_dasha, ayurveda.calculate_ayurvedic_constitution, and it is the birth_data kwarg of forecast.forecast_transits; the instant alone (date, time, timezone) is the kwargs for human_design.generate_bodygraph, chinese_astrology.generate_bazi_chart, and kabbalah.generate_birth_profile. Never look the city up twice for one person.

Sync calls (default)

horoscope = roxy.astrology.get_daily_horoscope(sign="aries")
card = roxy.tarot.draw_cards(count=3)
life_path = roxy.numerology.calculate_life_path(year=1990, month=1, day=15)

Async calls (append _async)

Every sync method has an async variant with _async suffix:

horoscope = await roxy.astrology.get_daily_horoscope_async(sign="aries")
card = await roxy.tarot.draw_cards_async(count=3)

POST endpoints (charts, spreads, calculations)

Most valuable endpoints are POST:

natal = roxy.astrology.generate_natal_chart(
    date="1990-01-15",
    time="14:30:00",
    latitude=40.7128,
    longitude=-74.006,
    timezone="America/New_York",
)

kundli = roxy.vedic_astrology.generate_birth_chart(
    date="1990-01-15",
    time="14:30:00",
    latitude=28.6139,
    longitude=77.209,
)

celtic = roxy.tarot.cast_celtic_cross(question="What should I focus on?")

numerology = roxy.numerology.generate_numerology_chart(
    full_name="John Doe",
    year=1990,
    month=1,
    day=15,
)

Multi-language via lang kwarg

10 languages: en, tr, de, es, hi, pt, fr, ru, zh-Hans, zh-Hant. Defaults to en. Supported: astrology, vedic_astrology, forecast, human_design, chinese_astrology, feng_shui, mesoamerican_astrology, vastu, numerology, kabbalah, tarot, biorhythm, ayurveda, iching, crystals, angel_numbers, languages. English-only: dreams, location, usage.

card = roxy.tarot.get_daily_card(date="2026-04-22", lang="es")
life_path = roxy.numerology.calculate_life_path(year=1990, month=1, day=15, lang="hi")

The two Chinese scripts (zh-Hans, zh-Hant) currently ship on Chinese astrology and feng shui; every other domain answers those codes in English per field. To list supported codes at runtime, call roxy.languages.list_languages().

Common tasks

In the catalog order (Western astrology, Vedic astrology, forecast, Human Design, Chinese astrology, feng shui, Mesoamerican astrology, Vastu, numerology, Kabbalah, tarot, biorhythm, Ayurveda, I Ching, crystals, dreams, angel numbers, location, usage, languages). birth is {"date": ..., "time": ..., "latitude": ..., "longitude": ..., "timezone": ...} from the two-step pattern above.

Task Code
Find city coordinates (do this first) roxy.location.search_cities(q="Berlin")
Daily horoscope roxy.astrology.get_daily_horoscope(sign=sign)
Natal chart (Western) roxy.astrology.generate_natal_chart(**birth)
Synastry roxy.astrology.calculate_synastry(person1=person1, person2=person2)
Compatibility score roxy.astrology.calculate_compatibility(person1=person1, person2=person2)
Current moon phase roxy.astrology.get_current_moon_phase()
Transits roxy.astrology.calculate_transits(natal_chart=natal_chart)
Kundli (Vedic birth chart) roxy.vedic_astrology.generate_birth_chart(**birth)
Panchang (detailed) roxy.vedic_astrology.get_detailed_panchang(date=date, latitude=latitude, longitude=longitude, timezone=timezone)
Choghadiya roxy.vedic_astrology.get_choghadiya(date=date, latitude=latitude, longitude=longitude, timezone=timezone)
Current dasha roxy.vedic_astrology.get_current_dasha(**birth)
Mangal Dosha roxy.vedic_astrology.check_manglik_dosha(**birth)
Guna Milan (matching) roxy.vedic_astrology.calculate_gun_milan(person1=person1, person2=person2)
Navamsa (D9) roxy.vedic_astrology.generate_navamsa(**birth)
KP chart roxy.vedic_astrology.generate_kp_chart(**birth)
KP ruling planets roxy.vedic_astrology.get_kp_ruling_planets(latitude=latitude, longitude=longitude, timezone=timezone)
Nakshatra detail roxy.vedic_astrology.get_nakshatra(id="ashwini")
Transit forecast roxy.forecast.forecast_transits(birth_data=birth, start_date=start_date, end_date=end_date)
Cross-domain timeline roxy.forecast.generate_timeline(birth_data=birth, start_date=start_date, end_date=end_date)
Human Design bodygraph roxy.human_design.generate_bodygraph(date=date, time=time, timezone=timezone)
Human Design connection roxy.human_design.calculate_connection(person_a=person_a, person_b=person_b)
BaZi Four Pillars roxy.chinese_astrology.generate_bazi_chart(date=date, time=time, timezone=timezone)
Chinese zodiac animal roxy.chinese_astrology.calculate_zodiac_animal(date=date)
Almanac day (Tong Shu) roxy.chinese_astrology.get_almanac_day(date=date)
Kua number roxy.feng_shui.calculate_kua_number(date=date, gender=gender)
Flying star natal chart roxy.feng_shui.generate_flying_star_chart(period=period, facing=facing)
Tzolkin day sign roxy.mesoamerican_astrology.calculate_tzolkin(date=date)
Full Maya chart roxy.mesoamerican_astrology.generate_mayan_chart(date=date)
Vastu entrance roxy.vastu.calculate_entrance_pada(plot=plot, facing=facing, door_position=door_position)
Vastu room compliance roxy.vastu.calculate_room_compliance(plot=plot, facing=facing, rooms=rooms)
Life path number roxy.numerology.calculate_life_path(year=year, month=month, day=day)
Full numerology chart roxy.numerology.generate_numerology_chart(full_name=full_name, year=year, month=month, day=day)
Personal year roxy.numerology.calculate_personal_year(month=month, day=day) (year is optional, 100 to 2100, and defaults to the current UTC year)
Gematria roxy.kabbalah.calculate_gematria(text=text)
Kabbalah birth profile roxy.kabbalah.generate_birth_profile(date=date, time=time, timezone=timezone)
Daily tarot card roxy.tarot.get_daily_card(seed=seed)
Three-card spread roxy.tarot.cast_three_card(question=question)
Celtic Cross roxy.tarot.cast_celtic_cross(question=question)
Yes / no tarot roxy.tarot.cast_yes_no(question=question)
Biorhythm reading roxy.biorhythm.get_reading(birth_date=birth_date)
Daily biorhythm reading roxy.biorhythm.get_daily_biorhythm(seed=seed)
Biorhythm forecast roxy.biorhythm.get_forecast(birth_date=birth_date)
Biorhythm compatibility roxy.biorhythm.calculate_bio_compatibility(person1=person1, person2=person2)
Ayurvedic constitution roxy.ayurveda.calculate_ayurvedic_constitution(**birth)
Dinacharya roxy.ayurveda.get_dinacharya_schedule(date=date, latitude=latitude, longitude=longitude, timezone=timezone)
Daily hexagram roxy.iching.get_daily_hexagram(seed=seed)
Cast I Ching reading roxy.iching.cast_reading()
Hexagram detail roxy.iching.get_hexagram(number="1")
Crystal by zodiac roxy.crystals.get_crystals_by_zodiac(sign=sign)
Crystal by chakra roxy.crystals.get_crystals_by_chakra(chakra=chakra)
Dream symbol lookup roxy.dreams.get_dream_symbol(id="flying")
Angel number meaning roxy.angel_numbers.get_angel_number(number="1111")
Universal number lookup roxy.angel_numbers.analyze_number_sequence(number="1234")
Check API usage roxy.usage.get_usage_stats()
List supported languages roxy.languages.list_languages()

Field formats that trip agents

These are the fields AI agents most often get wrong. Copy the format column exactly.

Field Format Good Bad
timezone IANA string (typed kwarg) OR decimal number (inside a dict[str, Any]) "Asia/Kolkata", "America/New_York", "Europe/London" as the top-level timezone= kwarg (server resolves to the DST-correct offset for the chart date). Decimal hours (5.5, -5, 0) work as JSON numbers and are accepted only inside person1/person2 dicts because the dict is typed dict[str, Any] - the top-level timezone= kwarg is typed str, so a quoted decimal like "5.5" is rejected server-side (validation_error). "5.5" as timezone= (rejected, server expects IANA string or a JSON number), "5:30", "+0530", "GMT-5"
date ISO date string "1990-01-15" "Jan 15 1990", datetime.now(), "15/01/1990", "1990-1-15"
time 24-hour string "14:30:00", "09:00:00" "2:30 PM", "14:30" (no seconds), "9:0:0" (no leading zeros)
latitude Decimal degrees (float) 51.5074 (London), -33.8688 (Sydney), 40.7128 (NYC) "28°36'N", "28 36 50", strings
longitude Decimal degrees (float) -0.1278 (London), -74.006 (NYC), 139.6917 (Tokyo) Same as latitude - no DMS strings
sign (horoscope kwarg) Lowercase zodiac name "aries", "taurus", "gemini", ... "pisces" "♈", "1" (the server matches case-insensitively, so "Aries" and "ARIES" work, but lowercase is canonical)
full_name (numerology) Birth-certificate name "John William Smith", "Priya Rajesh Sharma" Nickname, married name, partial name - affects all letter-based calcs
seed Any string (deterministic) "user-42", "session-abc-123", email hash Numbers, objects - must be string
number (angel numbers) String "1111", "777", "1234" 1111 (int) fails path validation
id (nakshatra / dream / tarot) Slug "ashwini", "flying", "the-fool", "three-of-cups" Display names, uppercase, spaces
house_system Enum string "placidus" (default), "whole-sign", "equal", "koch" "Placidus", "whole_sign", "WS"
ayanamsa (KP) Enum string "kp-newcomb" (default), "kp-old", "lahiri", "custom" "KP", "New Comb", "Lahiri"
node_type Enum string "mean" (smoothed node, traditional Vedic default), "true" (osculating node with perturbation corrections) "true-node", "mean-node", "True Node"
count (tarot draw) Integer 1 to 78 3, 10, 78 0, 79, strings, floats
mahadasha (path) Planet name "Ketu", "Venus", "Sun", "Moon", "Mars", "Rahu", "Jupiter", "Saturn", "Mercury" "KETU" (works, case-insensitive), "ke", "Ke-tu"
person1 / person2 Dict with full birth data {"date": ..., "time": ..., "latitude": ..., "longitude": ..., "timezone": ...} (Western) or same without timezone (Vedic) Separate top-level kwargs, missing time, partial dict
question (tarot / iching) Optional string "Should I accept the job offer?", "What should I focus on this week?" Omit for general reading. More specific = better interpretation.
year / month / day (numerology) Integer 1990, 1, 15 Zero-padded strings "01", floats, full dates

Timezone cheat sheet (most-asked locations)

Values are decimal hours. For the typed top-level timezone= kwarg, pass the IANA name from roxy.location.search_cities (timezone="America/New_York") - the server resolves it to the correct DST offset for the chart date. Inside a person1/person2 dict the bare decimal works because the dict is typed dict[str, Any], so the JSON-number form below is accepted.

Region Decimal Region Decimal
UTC / London (winter) 0 Dubai 4
London (summer, BST) 1 Karachi 5
Berlin / Paris 1 (winter) / 2 (summer) Delhi (IST) 5.5
Istanbul 3 Kathmandu (NPT) 5.75
Moscow 3 Dhaka 6
Tehran 3.5 (winter) / 4.5 (summer) Bangkok 7
Adelaide 9.5 (winter) / 10.5 (summer) Singapore / Beijing 8
New York (EST / EDT) -5 / -4 Tokyo 9
Chicago (CST / CDT) -6 / -5 Sydney 10 (winter) / 11 (summer)
Denver (MST / MDT) -7 / -6 Auckland 12 (winter) / 13 (summer)
Los Angeles (PST / PDT) -8 / -7 Honolulu -10

DST matters. If the birth date falls inside a daylight-saving window, use the summer / DST offset, or pass the IANA string from the location lookup and let the server resolve it. India observes no DST, so a fixed 5.5 is always right there; anywhere else, a natal chart must carry the offset in force at the time of birth.

Astrology domain gotchas for LLMs

LLMs hallucinate confidently in this category. These are the specific traps you will hit when writing client code:

  • Ayanamsa is server-side in Vedic. LLMs default to tropical / Western math. Vedic endpoints apply sidereal Lahiri ayanamsa server-side. KP endpoints accept ayanamsa of kp-newcomb (default), kp-old, lahiri, or custom. Do not try to "correct" server output by subtracting ayanamsa in client code.
  • Tithi count is 30, not 2. 15 Shukla (waxing) plus 15 Krishna (waning). Older LLM training data conflates Purnima and Amavasya as single tithis. Our panchang response carries a paksha field ("Shukla" or "Krishna") plus a tithi number, so there are 30 distinct tithis in a lunar month.
  • Rahu and Ketu are shadow points, not planets. They do not appear in a real ephemeris. Endpoints accept node_type of "mean" (smooth mean node, traditional Vedic default) or "true" (osculating node with perturbation corrections) to select which calculation to use.
  • Nakshatra count is 27. Abhijit is sometimes treated as a 28th in some schools, but this API uses the standard 27. roxy.vedic_astrology.list_nakshatras() returns a list of length 27.
  • Retrograde is per-planet, not global. Natal chart planets and Vedic meta include isRetrograde: bool per planet. KP planet lists use retrograde. Never generate "Mercury retrograde globally" UI copy, check the specific planet in the response.
  • Tarot reversals are a product choice. allow_reversals=False on a tarot draw means no reversed cards in that draw, period. It is not cosmically meaningful, it is a config flag.
  • Angel number lookup works for any positive integer. Digit-root fallback covers non-canonical numbers. Do not generate validation logic that rejects anything other than 111 / 222 / 333.
  • Seed-based daily endpoints are DETERMINISTIC per (seed, date) pair. Same seed plus same date returns the same reading. This is by design for push-notification consistency. Do not describe it as "cached" or retry on stale responses.
  • Timezone affects Western calculations more than Vedic. Western natal charts must respect DST at the time of birth. Vedic endpoints default to IST (5.5) which is DST-free. Pass the IANA timezone string from the location lookup ("America/New_York", "Asia/Kolkata") directly to chart calls and the server resolves the DST-correct offset for the chart date. Never pass the utcOffset of the city record (the offset in force today) or the clock of the user right now.

Error handling

Errors raise RoxyAPIError with error (message), code (machine-readable), status_code, doc_url (documentation for the code), retry_after (seconds from the Retry-After header, or None) and issues (the failing fields of a validation_error, otherwise None). ErrorCode is a string enum of every code below, so e.code == ErrorCode.RATE_LIMIT_PER_MINUTE works:

from roxy_sdk import create_roxy, ErrorCode, RoxyAPIError

try:
    result = roxy.astrology.get_daily_horoscope(sign="invalid")
except RoxyAPIError as e:
    if e.code == ErrorCode.VALIDATION_ERROR:
        for issue in e.issues or []:
            print(issue["path"], issue["message"], issue["code"])  # path is the dot-separated field, e.g. "time" or "person1.date"
    print(e.code)  # "validation_error"
    print(e.status_code)  # 400

Every error returns { error, code, doc_url }. Switch on code; error is readable text and may change. Each meaning below says whether and when to retry, and Retry-After carries the wait when the response sends it. Every code is documented at https://roxyapi.com/docs/errors.

Status Code Meaning
400 validation_error A field is missing or invalid. The body lists every failing field at once in issues, each with its path and the expected shape.
400 bad_request The request was rejected as a whole, for example a body that is not valid JSON or a date range that ends before it starts.
400 date_out_of_range A date lies outside the span the planetary positions are served for. The error names the supported dates.
401 api_key_required No API key was sent.
401 invalid_api_key The key sent is malformed or cannot be verified.
401 api_key_revoked The key was valid once and has since been revoked from the account page.
401 subscription_not_found The key verifies, but the subscription behind it no longer exists.
401 subscription_inactive The subscription behind the key is cancelled, expired or suspended, or a trial is past its end date.
401 publishable_key_not_allowed_on_mcp A publishable key was used on a Remote MCP server, which takes a secret key.
401 invalid_client_ip A keyless request could not be attributed to a caller.
401 unauthorized Authentication failed with no more specific reason to give.
403 forbidden The key is valid, but this request is not permitted.
403 origin_required A publishable key with an origin allowlist was used with no Origin header, as from a server or a native app.
403 origin_not_allowed The calling site is not on the origin allowlist of this publishable key.
404 not_found Nothing is served at this path, or the identifier in it does not exist. A path miss adds suggestions, the closest real endpoints.
405 method_not_allowed The path exists for a different HTTP method. The body lists the accepted methods in allow, as does the Allow header.
409 conflict The request cannot be applied in the current state.
410 gone The path was removed permanently.
413 payload_too_large The request body is larger than the API accepts. A body far over the cap is refused before it reaches the API and returns a bare 413 with no JSON body.
415 unsupported_media_type A request with a body was sent without Content-Type: application/json.
422 unprocessable_entity Every field is valid, but the combination cannot be computed.
429 rate_limit_exceeded The monthly request allowance is used up. Retry-After gives the seconds to the reset.
429 rate_limit_per_minute The per-minute limit of the plan was reached. Retry-After gives the seconds to the next minute, and the monthly allowance is not charged.
429 rate_limited A rate limit was reached, reported without the plan detail.
429 free_tier_exhausted A keyless request has used up its trial allowance.
500 internal_error The request failed inside our service. Retry with exponential backoff.
503 compute_saturated Heavy calculations are briefly at capacity. Send the same request again after Retry-After seconds.
Any error A fallback for a status with no more specific code. The status and the error field carry the signal.

Retries

The client retries twice by default: HTTP 429, 500, 502, 503 and 504, plus connection failures where the request was never sent. Pass max_retries to change the count, or max_retries=0 to turn retries off. Waits use the Retry-After header when present, otherwise jittered exponential backoff from initial_delay (default 0.5 seconds) up to max_delay (default 30 seconds). A Retry-After longer than max_delay, such as the one on rate_limit_exceeded, is not waited out: the error is raised with retry_after set. A retry never sleeps past timeout. Read timeouts are never retried.

from roxy_sdk import create_roxy, RoxyAPIError

roxy = create_roxy("your-api-key", max_retries=4)

try:
    result = roxy.astrology.get_daily_horoscope(sign="aries")
except RoxyAPIError as e:
    print(e.code)  # "rate_limit_per_minute", "compute_saturated", "validation_error", ...
    print(e.doc_url)  # documentation page for that code
    print(e.retry_after)  # seconds the server asked you to wait, or None

MCP equivalents

Every method has a matching MCP tool. The remote MCP server per domain is at https://roxyapi.com/mcp/{domain} (Streamable HTTP, no stdio / no self-hosting). Tool names follow {method}_{path_snake_case}, for example:

  • POST /astrology/natal-chart -> post_astrology_natal_chart on /mcp/astrology
  • GET /astrology/horoscope/{sign}/daily -> get_astrology_horoscope_sign_daily on /mcp/astrology
  • POST /vedic-astrology/birth-chart -> post_vedic_astrology_birth_chart on /mcp/vedic-astrology
  • POST /tarot/spreads/celtic-cross -> post_tarot_spreads_celtic_cross on /mcp/tarot

Use the SDK for typed Python apps. Use MCP for AI agents (Claude Desktop, Cursor MCP, OpenAI agents) where the agent selects tools based on user intent.

Gotchas

  • Geocode first. Any chart, panchang, synastry, compatibility, or natal endpoint needs coordinates. Call roxy.location.search_cities before the chart method.
  • All parameters are keyword arguments. Use sign="aries" not positional "aries".
  • Async methods end with _async. Every sync method has a matching async variant.
  • Do not expose API keys client-side. Call Roxy from server code only.
  • Date format is YYYY-MM-DD, time is HH:MM:SS. Both are strings.
  • Western timezone is required as an IANA string ("Asia/Kolkata", "America/New_York", "Europe/London", "UTC"); the server resolves it to the DST-correct offset for the chart date. Vedic endpoints accept an optional timezone (same form) that defaults to IST when omitted. The decimal-number form (5.5) is also accepted by the API, but only inside person1/person2 dicts - the top-level timezone= kwarg is typed str.
  • Errors raise RoxyAPIError. Catch it and check e.code, e.error, and e.status_code.
  • A validation_error carries issues, each with path (the dot-separated field, such as time or person1.date), message and code. Loop over them to show every failing field:
    except RoxyAPIError as e:
        for issue in e.issues or []:
            print(issue["path"], issue["message"], issue["code"])
  • Switch on e.code, not e.error. The message may change; the code is stable.
  • A city record has city, province, country, iso2, latitude, longitude, timezone, utcOffset and population. The name is city, never name.
  • utcOffset on a city record is the offset in force today. Pass the IANA timezone string to chart calls so the server resolves the offset for the birth date.
  • A natal chart planets is a list of objects. Find a body by name: next(p for p in chart["planets"] if p["name"] == "Moon").
  • In a Vedic chart meta.Moon.rashi is a string and meta.Moon.nakshatra is an object (name, pada, lord). Display kundli["meta"]["Moon"]["nakshatra"]["name"].
  • sign is matched case-insensitively. Lowercase is canonical.
  • Total requests on a persistent failure = 1 + retries. The default max_retries of 2 makes 3 requests; max_retries=0 makes exactly one.
  • List endpoints return a paginated envelope, {"total": ..., "limit": ..., "offset": ...} plus a named list (cities, crystals, hexagrams, symbols), never a bare list. Pass limit= to widen a page; list_hexagrams defaults to 20 of 64.

Links