Turn one birth input into every core chart, Western astrology, Vedic, Human Design, BaZi, and numerology, assembled into a single structured profile your AI agent reads before it answers anything about a person. One key, one fan-out. Cache birth-derived data separately from current readings.
An AI agent that talks about someone's chart needs the chart in front of it first. Ask an LLM for a natal chart from memory and it hallucinates degrees, houses, and dasha dates. The fix is to compute the real profile once from verified data and feed it to the model as grounded context.
This guide builds that profile: the location lookup, the five chart domains under one key, the Vedic and Chinese sub-charts, and keeping calculated values distinct from editorial interpretations. Reuse the interpretations in the UI or write your own reading, and pass the model the fields its question needs.
What you can build
The context block an AI astrology chatbot reads before every reply (grounding layer, stops hallucinated charts)
A per-user "profile memory" row for an AI companion, computed once at signup
A practitioner one-sheet: a client's full cross-domain chart on a single screen
A RAG document per person for a spiritual-insight product
Multi-domain dashboards (natal wheel + kundli + numerology card from one payload)
The person's birth date, time, full name, and city (you geocode the city in Step 1).
A backend you control (Next.js route, Vercel function, Cloudflare Worker, Bun server). The client never sees the secret key.
A persistent store (Postgres, SQLite, Redis, even a JSON column) to cache the assembled profile. Cache birth-derived results by the complete input and calculation version. Current readings need their own expiry.
Install
bash
npm install @roxyapi/sdk
bash
pip install roxy-sdk
bash
composer require roxyapi/sdk
bash
dotnet add package RoxyApi.Sdk
bash
go get github.com/RoxyAPI/sdk-go
bash
cargo add roxyapi
cargo add tokio --features macros,rt-multi-thread
The worked code below is TypeScript, the reference implementation. Every operation is also available in the other SDKs. The next section maps the method shape per language.
The shape: one input, five domains, one profile
Every call below takes the same birth data. The lead chart is the natal chart (Western); Vedic is the second domain, then Human Design, BaZi and numerology, with the Vedic and Chinese sub-charts deepening them. One key covers all of them, no per-domain fees.
Call
Domain
Endpoint
operationId
Returns
1
Location
GET /location/search
searchCities
latitude, longitude, timezone
2
Western
POST /astrology/natal-chart
generateNatalChart
planets, houses, aspects, ascendant, midheaven
3
Vedic
POST /vedic-astrology/birth-chart
generateBirthChart
rashi chart, planets with nakshatra and pada, yogas
strong or weak verdict, decade timeline, personal directions
Rule 0: location first
Western and Vedic charts need birth coordinates and timezone. Resolve the city once, let the user confirm the match, and reuse those values where the endpoint accepts them. Other domains have different input requirements, listed below.
Call it from any SDK
The same operations exist in the TypeScript, Python, PHP, C#, Go, and Rust SDKs. TypeScript, Python, PHP, Go and Rust name each method after the operationId from the shape table above (camelCase in TypeScript and PHP, snake_case in Python and Rust, PascalCase in Go); C# is path-fluent and mirrors the URL. Here is the canonical call, the natal chart, in each:
use function RoxyAPI\Sdk\createRoxy;
$roxy = createRoxy(getenv('ROXY_API_KEY'));
$natal = $roxy->astrology->generateNatalChart(
date: '1990-07-15', time: '14:30:00',
latitude: 40.7128, longitude: -74.006, timezone: 'America/New_York');
csharp
using RoxyApi;
using Microsoft.Kiota.Abstractions;
var roxy = new RoxyClient(Environment.GetEnvironmentVariable("ROXY_API_KEY")!);
var natal = await roxy.Astrology.NatalChart.PostAsync(new() {
Date = new Date(1990, 7, 15), Time = new Time(14, 30, 0),
Latitude = 40.7128, Longitude = -74.006,
Timezone = new() { String = "America/New_York" } });
use roxyapi::{Roxy, types};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let roxy = Roxy::new(std::env::var("ROXY_API_KEY")?)?;
let birth = types::NatalChartRequest::new(
"1990-07-15".into(), "14:30:00".into(), 40.7128, -74.006,
types::NatalChartRequestTimezone::String("America/New_York".into()),
);
let natal = roxy.astrology().generate_natal_chart(&Default::default(), &birth).await?;
println!("Ascendant: {}", natal.ascendant.sign);
Ok(())
}
The other four charts follow the identical pattern: generateBirthChart, generateBodygraph, generateBaziChart, and generateNumerologyChart (path-fluent roxy.VedicAstrology.BirthChart, roxy.HumanDesign.Bodygraph, roxy.ChineseAstrology.Bazi.Chart, roxy.Numerology.Chart in C#); numerology takes { fullName, year, month, day } instead of the location body, and BaZi needs only date, time and timezone. The full per-method list, with request and response types in every language, ships in each SDK's bundled AGENTS.md and in the Agent Task Cheatsheet, both generated from the same spec so they never drift.
Step 1: Location lookup (run once per person)
Convert the free-text city to coordinates and a timezone with the Location API, then reuse the result in every chart call. The raw contract is one authenticated GET; the SDK wraps the same request.
Save { latitude, longitude, timezone }. The IANA timezone string resolves server-side to the DST-correct offset for the birth date, so a July 1990 New York birth gets EDT automatically.
Step 2: The five core charts (reuse one birth input)
The natal chart, the Vedic kundli, the Human Design bodygraph, the BaZi chart, and the numerology chart are the foundation. Reuse the saved birth input across these calls. Cache the birth-derived fields separately from date-dependent fields such as the numerology personal year. Numerology takes { year, month, day } integers plus the birth-certificate fullName, and an optional targetDate: send the local date of the user so the age, the maturity status and the personal cycles turn over on their own day. The chart endpoints take the location from Step 1. Human Design and BaZi require date, time and timezone; coordinates do not sharpen Human Design planetary positions. Reuse only the fields each endpoint accepts.
Swap the path for /vedic-astrology/birth-chart, /human-design/bodygraph or /chinese-astrology/bazi/chart with the same body; /numerology/chart takes {"fullName":"Emma Charlotte Wright","year":1990,"month":7,"day":15}.
Kundli (kundli.data): meta.{Graha}.{ rashi, longitude, nakshatra: { name, pada, lord }, house, awastha, isRetrograde } for Sun through Ketu plus Lagna, twelve sign-keyed house entries, and yogas[].
Human Design (bodygraph.data): type, strategy, authority, profile, plus centers, channels, gates, and incarnationCross.
BaZi (bazi.data): pillars[].{ position, id, stem, branch, tenGod, hiddenStems, naYin } for year, month, day and hour, plus dayMaster.{ element, polarity }, fiveElements[].{ element, count, level }, interactions[], zodiacAnimal, and the conventions the chart was built with.
Never ship a secret sk_ key to a browser. Run every call from a backend you control. For widget or no-code embeds, mint a publishable pk_ key locked to your origins instead.
Step 3: Add Vedic depth
For a full profile, layer the Vedic sub-charts on the same birth body. Each is one call, all under the same key.
Verified operationIds: getCurrentDasha, generateNavamsa, detectYogas, checkManglikDosha, checkKalsarpaDosha, checkSadhesati, calculateAshtakavarga, calculateShadbala, generateKpChart. For the full 120-year timeline instead of just the running period, swap getCurrentDasha for getMajorDashas.
The Jaimini layer
Arudha padas and Chara Karakas complete the classical profile. Both take the same birth object, so they join the same fan-out:
Verified operationIds: calculateArudhaPadas, calculateCharaKarakas. The avastha readings referenced by the birth chart are served separately by listAvasthas (GET /vedic-astrology/avasthas) and getAvastha.
calculateArudhaPadas returns the twelve Jaimini padas (AL through UL) with the derivation attached. calculateCharaKarakas returns the ranked karaka offices plus atmakaraka and darakaraka at the top level.
scheme is a BODY field, not a query parameter. Passing it in the query string is ignored rather than rejected, so the call returns 200 with the default eight ranking and nothing signals the choice was dropped. The two schemes can name a different Atmakaraka for the same birth.
What each adds: getCurrentDasha returns the running mahadasha, antardasha, and pratyantardasha lords (the timing layer). generateNavamsa returns the D9 chart. detectYogas returns 48 verdicts, the 12 classical, all 32 Nabhasa and the four wealth and poverty verdicts, each as yogas[].{ name, present, quality, family, evidence }. Each dosha returns { present } plus details when present. calculateShadbala returns per-planet strength in rupas; calculateAshtakavarga returns bindu totals per sign.
Step 3b: Add Chinese metaphysics depth
The BaZi chart from Step 2 has the same relationship to the Chinese layer that the kundli has to the Vedic one: everything else reads off it. Three more calls complete it, and all three are deterministic from immutable birth data, so they cache alongside the rest of the profile.
What each adds: calculateDayMasterStrength returns the verdict (strong or weak), a numeric score, the three factors that produced it, and the favorableElements and unfavorableElements every downstream recommendation reads. calculateLuckPillars returns the ten-year cycles with startAge, startYear and endYear, which is the timing layer, the Chinese counterpart of a dasha. calculateKuaNumber is the feng shui entry point: one date plus a formula selector returns the personal number, the east or west group, and all eight compass directions ranked, which is what a placement or direction feature is built on.
`gender` is required on two of these, and it selects a formula
calculateLuckPillars needs it because the direction the pillars run depends on it, and calculateKuaNumber needs it because the two formula variants are different arithmetic. Neither derives from the chart. Both accept male or female. Label the input in your UI in whatever way suits your users.
Store the `conventions` object with the profile
Every BaZi response carries conventions (dayBoundary, yearBoundary, hourClock), the three school settings the chart was built with. Persist it beside the chart. When a user asks why your reading disagrees with one their teacher drew, that object is the answer, and without it you cannot reproduce your own output later. Details in the Chinese astrology guide.
Step 4: Assemble one profile in a single server route
Fan out every call behind one route and return a single payload. This combined response includes current dasha, Sade Sati and annual numerology. Fetch current readings fresh or give them an explicit expiry; cache natal results separately if needed.
Use the authenticated application session to select the saved profile. Never trust an arbitrary userId query parameter to authorize access to private birth data. Reuse the parallel calls in Steps 2 and 3 after that authorization check. Return only the data that account is permitted to read.
Handle SDK errors before assembling this object. The example above assumes the calls succeeded.
Step 5: Strip to core numbers for the agent
The responses can include editorial interpretation text alongside calculated values. Keep both available: your product can render that text or write its own interpretation. Trim only fields the model does not need for its actual question. The example below selects a compact set of fields for chart questions.
That object contains structured chart values and current readings. Persist birth-derived values as profile memory, and refresh current dasha and Sade Sati before treating them as current.
Step 6: Feed it to your LLM as grounded context
Inject the stripped profile into the system prompt. The model now answers from real, verified positions instead of inventing them, and writes in your product's voice.
typescript
const context = toAgentContext(profile);
const system = `You are the in-app astrologer for Acme Stars. Warm, specific, never vague.
Answer ONLY from the verified birth profile below. Never invent positions, degrees, or dates; if a question needs data not present here, say so.
Reply in the user's language. Keep domain terms (planet, nakshatra, gate) in their original form. Never mention APIs, tools, or that this profile was precomputed; speak as if you simply know it. End with one actionable insight.
BIRTH PROFILE (verified, core numbers only):
${JSON.stringify(context, null, 2)}`;
// Pass `system` to your model (OpenAI, Anthropic, Gemini, or any provider).
This is the profile-context pattern: reuse birth-derived data and refresh current readings before grounding replies on them. For the live tool-calling variant, where the model fetches charts mid-conversation, the open-source astrology-ai-chatbot template ships a production system prompt (location-first procedure, ambiguous-date disambiguation, multilingual replies, never reveal the tools) worth adapting.
For a chatbot that should also fetch fresh data mid-conversation (today's transits, a compatibility score with another person), keep this profile as the base context and add the per-domain Remote MCP servers so the agent can call verified tools live on top of it.
Optional layers and what is left out
The five charts plus the Vedic and Chinese depth above combine a birth-derived profile with current readings. More layers are available when a product needs them, all on the same key and the same birth body:
More Western depth.POST /astrology/asteroids, POST /astrology/arabic-lots, and POST /astrology/fixed-stars add natal points and bodies the core chart does not return.
More Vedic depth.POST /vedic-astrology/divisional-chart for any varga beyond D9 (D10 career, D7 children, and so on), POST /vedic-astrology/upagraha for the subtle calculated points, POST /vedic-astrology/bhava-bala for house strength, POST /vedic-astrology/bhav-chalit for the cusp-based house shifts, and POST /vedic-astrology/dasha/sub/{mahadasha} for sub-period drill-down.
More Human Design depth.POST /human-design/variables returns the four arrows (determination, environment, perspective, motivation) on the same birth body.
More Chinese depth.POST /chinese-astrology/bazi/compatibility scores two charts against each other for matchmaking, and POST /feng-shui/eight-mansions expands the Kua number into the full ranked direction map with a reading per sector.
Mesoamerican day signs.POST /mesoamerican-astrology/mayan/chart returns the Tzolkin day sign and trecena, the Long Count and the Calendar Round, and POST /mesoamerican-astrology/aztec/tonalpohualli the Aztec day sign, both from the birth date alone.
More numerology.POST /numerology/chaldean returns the Chaldean (Cheiro) compound numbers alongside the Pythagorean chart, POST /numerology/dual sets the two systems side by side for one name, and POST /numerology/bridge returns the bridge numbers between the core numbers.
Kabbalah.POST /kabbalah/birth-profile returns the Hebrew birth date, the next Hebrew birthday and the birth angels; POST /kabbalah/name-profile reads the name through gematria.
Ayurveda.POST /ayurveda/constitution returns the dosha constitution (vata, pitta, kapha shares) read from the sidereal chart.
Lifestyle layer.GET /crystals/birthstone/{month} and GET /crystals/zodiac/{sign} map the birth month and sun sign to stones.
Deliberately left out of the static profile:
The dynamic layer. Transits, progressions, solar and lunar returns, profections, the BaZi annual forecast, the flying star and affliction overlays, and the forecast timeline change with the calendar, so they are computed live, not cached into the profile. Add them at request time over Remote MCP on top of the cached profile.
Non-birth domains. Tarot, I Ching, dreams, and angel numbers are not derived from birth data (a tarot draw is random, an angel number is a lookup), so they are not part of a birth profile.
Biorhythm is birth-date driven but cyclical (it changes every day), so treat it as a daily metric, not a static profile field.
Gotchas
Numerology takes integers, not a date string.{ year, month, day }, not 1990-07-15. The fullName is the birth-certificate name, used for the letter-based numbers (expression, soul urge, personality). targetDate is a date string: today in the zone of the user.
A few birth endpoints take a different body./astrology/solar-return takes birthDate, birthTime and returnYear; the biorhythm routes take birthDate; /kabbalah/birth-profile takes date, time and timezone with no coordinates; /mesoamerican-astrology/mayan/chart and /mesoamerican-astrology/aztec/tonalpohualli take date only; /feng-shui/kua takes date and gender. Map the saved birth input per call.
The Vedic kundli is keyed by sign and by graha.generateBirthChart returns a twelve sign-keyed house map plus a meta object keyed by planet. Read meta.{Graha} for a clean per-planet view; do not expect a flat planets[] array like the Western chart.
Human Design and BaZi need only date, time, and timezone. Coordinates are optional on both, so they are the two charts that still work when the birth city is unknown. Read type, strategy, authority, and profile from the Human Design response, and pillars, dayMaster and conventions from the BaZi one.
The BaZi chart is read right to left, and stores its own school settings.pillars[0] is the year and pillars[3] is the hour, while the conventional presentation puts the hour on the left, so reverse the array when you render. Persist conventions with the chart: it is the only thing that lets you reproduce the same pillars later.
Select context for the question. Keep calculated values distinct from editorial readings. Retain interpretations for the UI or model when useful; omit unnecessary fields to reduce input tokens.
Separate natal and current caches. Include complete birth inputs, chosen conventions and calculation version in natal cache keys. Current dasha, Sade Sati, annual numerology, the numerology maturity status and the next Hebrew birthday need expiry and refresh.
One plan, every domain. All the calls above bill at a flat 1 request each, REST and MCP identical. No per-domain fees, no batch endpoints.
Positions are read directly from the NASA JPL DE440 ephemeris and verified against NASA JPL Horizons. The same Roxy Ephemeris powers the Western, Vedic, Human Design, and KP layers, so every domain agrees on the same sky.
Frequently asked questions
How many API calls does a full profile take?
One location lookup plus one call per chart. The five core charts (Western, Vedic, Human Design, BaZi, numerology) are the minimum; the Vedic sub-charts (dasha, navamsa, yogas, doshas, ashtakavarga, shadbala, KP) and the Chinese ones (Day Master strength, luck pillars, feng shui Kua) add one call each. All run in parallel and bill at a flat 1 request each.
Why strip the interpretations before sending to an LLM?
Select fields for the question rather than forwarding every response. Omitting unnecessary prose can reduce input tokens. Keep editorial interpretations available for display or for questions that need them, and keep calculated values distinct from model-written readings.
Can I cache the assembled profile?
Cache birth-derived values for identical inputs and calculation conventions. Refresh date-dependent values such as current dasha, Sade Sati and personal year. Invalidate natal caches after corrected birth inputs or a calculation update.
Do I need a separate subscription for Western, Vedic, Human Design, BaZi, and numerology?
No. One API key covers every domain in the catalog. The whole profile is built from a single subscription with flat per-request pricing and no per-domain fees.
What endpoints make up a complete birth profile?
The deterministic, birth-derived ones: astrology/natal-chart, vedic-astrology/birth-chart (plus dasha, navamsa, yogas, doshas, ashtakavarga, shadbala, and kp/chart), human-design/bodygraph, chinese-astrology/bazi/chart (plus bazi/day-master, bazi/luck-pillars and feng-shui/kua), and numerology/chart. The examples also add current dasha, Sade Sati and annual numerology, which must be refreshed. Other time-varying data (transits, returns, forecast, annual stars) and non-birth domains (tarot, I Ching, dreams, angel numbers) remain separate.
The MCP setup connects your agent to live verified tools so it can fetch fresh data on top of the cached profile.
R
RosieYour AI guide to RoxyAPI
R
Hi, I am Rosie, your guide to the RoxyAPI insight tools.
Ask me to read your birth chart, pull a card, or map your numbers, and I will interpret what it means for you. Unlike most AIs, I never make the numbers up: every reading runs on real, verified calculations. Curious about the API, pricing, or docs instead? Ask me that too.