A JSON HTTP API over the Jagannatha Hora calculation engine. Send a birth date, time and place; get back the full Vedic chart — 23 divisional charts, dashas, yogas, doshas, ashtakavarga, transits, panchang, muhurta and compatibility. Seventeen endpoints, sixteen of them open with no API key.
Last verified against the service source on 2026-08-31.
Start here
The API is live at https://jagannatha-hora-359167915530.europe-west1.run.app. There is nothing to sign up for. Send a POST with a JSON body and read the JSON that comes back. This one command returns a complete Vedic birth chart:
If you do not know the coordinates for a birth place, resolve it first with GET /location/search, which searches a local index of 162,000+ cities and returns latitude, longitude and the timezone offset. That is the normal two-step flow: one lookup, then one calculation.
If you are wiring this into an AI agent rather than an application, use the MCP server instead. It exposes the same engine as 32 individually callable tools, so a model can ask for just the dashas or just the ashtakavarga and get kilobytes back rather than the megabytes /horoscope returns.
Machine-readable versions of this page
This page exists in three more formats. They carry the same facts and are kept in sync by a test that fails the build when they drift.
horoscopes.today/openapi.json — OpenAPI 3.1 description of every endpoint below. Point a code generator, an HTTP client or an agent at this rather than parsing prose.
horoscopes.today/api.md — This entire reference as plain Markdown, for LLM fetchers and anything else that would rather not strip HTML.
Every endpoint on this list except POST /horoscope/pdf is open — no key, no token, no signup. CORS is wide open, so browser-side calls work too. The one gated endpoint uses a shared secret in the X-PDF-Secret header and is reserved for the site's own backend.
Rate limits are real
Limits are enforced per client IP by the service itself. The app-wide default is 200 requests/minute per IP; several endpoints set a tighter one, listed with each endpoint below. Exceeding a limit returns 429.
Everything is deterministic
The same inputs always produce the same output — these are astronomical calculations, not model inferences. Cache aggressively on your side. /panchang, /gochar and /gochar/events additionally send Cache-Control: public, max-age=21600.
Dates and times
Dates are YYYY-MM-DD and times are HH:MM:SS on a 24-hour clock, always as strings, never epoch numbers. Timezones are a decimal hour offset from UTC (5.5, not "Asia/Kolkata"). For birth moments the service re-resolves the historically correct, DST-aware offset from the coordinates and date, so a slightly wrong offset is usually corrected for you.
Responses are gzipped
Responses over 1 KB are gzip-compressed. This matters most for /horoscope, where it turns megabytes into hundreds of kilobytes. Send Accept-Encoding: gzip — every HTTP client does by default.
Validation happens twice
FastAPI rejects a structurally wrong body with 422 before the handler runs; the field validators then reject out-of-range values with 400 and a message naming the field and the bound. Read the detail string — it tells you exactly which field failed and why.
The shared birth-details block
Six endpoints take a birth chart as their subject: /horoscope, /horoscope/pdf, /gochara, /gochara/range, /muhurta and /saturn-timeline. They all start from the same block of fields, listed once here rather than repeated six times below. Only the first six are required; everything after elevation is a calculation setting with a sensible default, and you can ignore all of them until you have a reason not to.
One caveat on scope: /horoscope and /horoscope/pdf accept every field in this table. The transit and muhurta endpoints take the first eight — through ayanamsa_mode — plus their own parameters, and /saturn-timeline accepts a narrower ayanamsa_mode than the rest. Each endpoint below says what it adds.
Birth details and calculation settings, from BirthDetailsRequest in api_server.py
Parameter
Type
Required
Default
Notes
date
string
Yes
—
Birth date, YYYY-MM-DD. Year must be 1900-2100, month 1-12, day 1-31.
time
string
Yes
—
Birth time, HH:MM:SS (24-hour). Hour 0-23, minute 0-59, second 0-59.
place
string
Yes
—
Birth place name. Cosmetic on the transit endpoints, where it defaults to an empty string; required on /horoscope.
latitude
number
Yes
—
Decimal degrees, -90 to 90.
longitude
number
Yes
—
Decimal degrees, -180 to 180.
timezone
number
Yes
—
UTC offset in hours, -12 to 14 (5.5 for IST). The service re-resolves the historical, DST-correct offset for the birth moment, so this is a hint rather than the last word.
elevation
number
No
0.0
Metres above sea level.
ayanamsa_mode
string
No
"LAHIRI"
One of 21 modes (see the ayanamsa list below). Case-insensitive; uppercased server-side.
ayanamsa_value
number
No
null
Custom ayanamsa in degrees, -30.0 to 30.0. Only meaningful with SIDM_USER.
calculation_type
string
No
"drik"
"drik" (modern) or "ss" (Surya Siddhanta). Case-insensitive.
node_type
string
No
"mean"
Rahu/Ketu node: "mean" or "true".
bhava_madhya_method
integer
No
1
House system, 1-5: 1=Equal-Lagna-Middle, 2=Equal-Lagna-Start, 3=Sripati, 4=KP, 5=Whole-Sign.
language
string
No
"en"
One of en, hi, ka, ta, te.
pravesha_type
integer
No
0
0=Natal, 1=Annual, 2=Tithi-Pravesha.
years
integer
No
1
Year number for annual/progressed charts, 1-120.
months
integer
No
1
Month number for monthly charts, 1-12.
sixty_hours
integer
No
1
60-hour period for hora progressions. The validator enforces 1-1000.
divisional_chart_factor
integer
No
1
1-300. 1=D-1 (Rasi), 2=D-2 (Hora), 9=D-9 (Navamsa), and so on.
chart_method
integer
No
1
1-6. Which classical construction to use for the divisional chart.
base_rasi
integer
No
null
0-11 (0=Aries, 11=Pisces), for custom charts.
count_from_end_of_sign
boolean
No
null
Count divisions backward in even signs.
varnada_method
integer
No
1
Positive integer.
tamil_month_method
integer
No
3
0=Ravi Annasamy, 1=V4.3.5, 2=10AM Start, 3=Midday UTC.
kali_start_year
integer
No
13
1=Prabhava (South Indian) or 13=Pramaadhi (North Indian).
Ayanamsa modes
The ayanamsa_mode field accepts these 21 values. Lahiri is the default and by far the most widely used in Indian practice; the choice shifts every sidereal longitude in the chart, so pick one and stay with it rather than comparing across modes.
Listed most useful first. Every one of them returns JSON except POST /horoscope/pdf, which returns a PDF.
POST/horoscope
The complete Vedic birth chart for a birth moment.
The workhorse endpoint. One call returns every calculation the engine performs for a chart: 23 divisional charts, nakshatras and padas, yogas, doshas, chara karakas, sahams, upagrahas, special lagnas, sphutas, arudhas, house relationships, planetary states, five kinds of bala, ashtakavarga, graha and rasi dashas, Saturn transits and a longevity band. The response is large — on the order of 3.5 MB of JSON — and gzip-compressed on the wire. Computed fresh every time; the same inputs always produce the same output, so cache it on your side.
Ask for a divisional chart with divisional_chart_factor, but note that divisional_charts already contains all 23 vargas regardless.
If you only need one slice of this — the dashas, the ashtakavarga, the yogas — the MCP server exposes each as its own tool and returns kilobytes instead of megabytes.
POST/horoscope/pdf
The same chart rendered as a downloadable PDF report.
Runs the identical calculation path as POST /horoscope — there is no second computation and no divergence — then typesets it as a designed report and returns application/pdf with a Content-Disposition of inline; filename="janma-kundali.pdf". Dosha presence and the birth panchanga are computed additionally for the cover; the /horoscope JSON response is unaffected. This is the one gated endpoint on the service.
Rate limit
10 requests/minute per IP
Authentication
X-PDF-Secret request header, compared against the server's HOROSCOPE_PDF_SECRET with a constant-time comparison. Fails closed — no secret configured on the server means every call is rejected. This endpoint is for the site's own backend, not for third-party integration.
HTTP/1.1 200 OK
content-type: application/pdf
content-disposition: inline; filename="janma-kundali.pdf"
%PDF-1.4 ...binary...
POST/marriage-match
Ashtakoota (North Indian) and 10 Porutham (South Indian) compatibility for two charts.
Takes two birth charts and scores them under both classical systems at once, then adds the Manglik-family dosha load for each person and the Beeja/Kshetra sphutas. The North Indian block scores the eight kutas out of 36; the South Indian block reports each of the ten poruthams as matched or not, with the minimum-porutham flag. It returns the computation, not a verdict.
Rate limit
Inherits the app default (200 requests/minute per IP) — this endpoint declares no limiter of its own
date, time, latitude, longitude, timezone (all required) and elevation (default 0.0). Note this nested model has NO place field and takes no calculation settings.
The two nested birth-detail objects are a different, smaller model than the one /horoscope takes — no place, no ayanamsa_mode, no chart settings.
POST/panchang
The full daily panchang for a date and place. No birth chart needed.
The five limbs — vara, tithi, nakshatra, yoga, karana — plus sun and moon rise/set, day length, the auspicious and inauspicious muhurta windows, day and night Choghadiya, the lunar month in both Amanta and Purnimanta reckoning, ritu, ayana, Shaka and Vikram Samvat with the sixty-year cycle name, and the Moon and Sun signs. Deterministic for a given date and place; the response carries Cache-Control: public, max-age=21600.
Rate limit
60 requests/minute per IP
Authentication
None. Open endpoint, no key required.
Response keys
panchang
Body fields for /panchang
Parameter
Type
Required
Default
Notes
date
string
Yes
—
YYYY-MM-DD. Rejects dates that do not exist on the calendar, e.g. 2026-02-31.
latitude
number
Yes
—
-90 to 90, and additionally |latitude| must be 66 or less — panchang is sunrise-anchored and undefined beyond the polar circles.
The polar restriction is a hard 400, not a degraded result: beyond ±66° the solar-crossing search would not terminate.
POST/gochar
Live planetary transits for a date and place. Birthless.
Where the natal chart is irrelevant: the nine grahas with sign and degree, nakshatra and pada, direct or retrograde motion, combustion flag, classical dignity (exalted, debilitated, moolatrikona, own), daily speed, and the date each next changes sign, nakshatra and pada — plus the Moon and Sun signs and the set of planets currently retrograde. Positions are geocentric and therefore identical worldwide at an instant; the place's timezone governs only what counts as "today" and how the dates are displayed. Cached 6 hours.
Rate limit
60 requests/minute per IP
Authentication
None. Open endpoint, no key required.
Response keys
gochar
Body fields for /gochar
Parameter
Type
Required
Default
Notes
date
string
Yes
—
YYYY-MM-DD; must be a real calendar date.
latitude
number
Yes
—
-90 to 90. No polar restriction — gochar is sunrise-free and well defined at every latitude.
Upcoming transit events over a date range. Birthless.
One merged, date-sorted list of sign changes for every requested planet, nakshatra changes for all of them except the Moon (which changes nakshatra roughly daily and would drown the list), and retrograde stations for Mars, Mercury, Jupiter, Venus and Saturn. Event dates are expressed in the requested timezone. Computed fresh.
Rate limit
60 requests/minute per IP
Authentication
None. Open endpoint, no key required.
Response keys
gochar_events
Body fields for /gochar/events
Parameter
Type
Required
Default
Notes
from_date
string
Yes
—
YYYY-MM-DD, a real calendar date.
to_date
string
Yes
—
YYYY-MM-DD. The range is capped at 90 days.
latitude
number
Yes
—
-90 to 90. Used for the display timezone.
longitude
number
Yes
—
-180 to 180.
timezone
number
Yes
—
UTC offset used to express event dates, -12 to 14.
place
string
No
""
Cosmetic.
planets
string[]
No
null
Planet names. Defaults to all nine: Sun, Moon, Mars, Mercury, Jupiter, Venus, Saturn, Rahu, Ketu.
A transit snapshot read against a natal chart, for one target date.
The natal counterpart to /gochar. Returns the panchanga for the target moment; the muhurta windows (sunrise, sunset, solar noon, Abhijit, and the Rahu, Gulika and Yamaganda periods to avoid); all nine planets with sign, degree, nakshatra and pada, retrograde and combust flags, and their house from both the natal Moon and the natal Lagna; and the person-relative strengths — Tara Bala from Moon, Sun and Lagna, Chandra Bala, and Sade Sati state. The event location is optional and defaults to the birth location. Computed fresh, no cache.
The same natal transit snapshot for every day in a range, in one call.
Built for the case where an AI agent should do the deciding. It returns the full per-day gochara detail — panchanga, muhurta windows including a clean Abhijit, planets, person-relative strength, ashtakavarga, gochara-phala and vedha — with no scoring and no "best date" verdict, so the caller reasons over the raw data itself. The natal reference is computed once and reused across the range. Computed fresh; the range is capped at 60 days.
Pass include: [] when you want the lean snapshot — omitting the field is not the same thing, and gives you everything.
POST/saturn-timeline
Sade Sati and Dhaiyya timing, with month-by-month pressure and relief bands.
Returns the sign-based Sade Sati cycles for a chart, whether one is running right now and which of the three phases it is in, how many months remain, and — derived from Saturn's kakshya in the Ashtakavarga — the classical relief share. detail="full" adds the month-by-month bands, the interruptions and the segments. This is computation, not interpretation: dates and supported/unsupported flags, nothing else.
Rate limit
60 requests/minute per IP
Authentication
None. Open endpoint, no key required.
Response keys
saturn_timeline
Body fields for /saturn-timeline
Parameter
Type
Required
Default
Notes
date
string
Yes
—
Birth date, YYYY-MM-DD.
time
string
Yes
—
Birth time, HH:MM:SS.
place
string
No
""
Cosmetic.
latitude
number
Yes
—
-90 to 90.
longitude
number
Yes
—
-180 to 180.
timezone
number
Yes
—
UTC offset, -12 to 14.
ayanamsa_mode
string
No
"LAHIRI"
ONLY "LAHIRI" or "RAMAN" here — narrower than every other endpoint. The two subsystems this endpoint drives honour only those two labels identically; anything else would silently compute a mismatched chart, so it is rejected with a 400 instead.
Every sidereal sign change for a set of planets across a date range.
Includes retrograde back-outs and re-entries, each crossing flagged so you can tell a temporary ingress from the one that sticks: a final_settling flag marks the last crossing of each sign boundary inside the window. Data only, computed fresh.
Rate limit
60 requests/minute per IP
Authentication
None. Open endpoint, no key required.
Response keys
planet_ingress
Body fields for /planet-ingress
Parameter
Type
Required
Default
Notes
planets
string[]
No
null
Planet names. Defaults to the slow movers: Saturn, Jupiter, Rahu, Ketu.
from_date
string
Yes
—
YYYY-MM-DD.
to_date
string
Yes
—
YYYY-MM-DD. The field description states a maximum of about 5 years.
timezone
number
No
0.0
UTC offset used to express the crossing dates, -12 to 14. Defaults to UTC, not to IST.
timezone defaults to 0.0 (UTC). A crossing near local midnight will look like it is on the previous day unless you pass your own offset.
POST/muhurta
Score every day in a range for an event, against classical muhurta rules and the native's own chart.
Scores each day by the classical factors — vara, nakshatra, tithi, paksha — and by the person's strength on that day: Tara Bala, Chandra Bala and Sade Sati state, per the rule table for the chosen event type. It returns the per-date factor data, a deterministic score with its breakdown and the weights used, and the auspicious Abhijit window plus the Rahu, Gulika and Yamaganda windows to avoid. It does not pick a date; the caller composes the recommendation. Computed fresh.
The event types POST /muhurta accepts, with their rule sources.
Call this first. It is the authoritative list of event_type values; sending anything not in it is a 400. Each entry carries a human label and the classical source the rule table came from.
Rate limit
Inherits the app default (200 requests/minute per IP)
The page does not reproduce the event list because it is defined in the service's rule table (gochara_rules.EVENT_RULES) and changes there, not here. Fetch it.
GET/location/search
Resolve a place name to coordinates and a timezone offset.
Resolves against a local index of 162,000+ world cities — instant, free, offline, and deterministic. No external geocoder is contacted. The single best match is returned. For "City, Country" inputs that do not match directly, the trailing qualifier is dropped and retried, so "Springfield, IL, US" falls back to "Springfield, IL". Use this to turn a user's typed birth place into the latitude, longitude and timezone the calculation endpoints need.
Rate limit
Inherits the app default (200 requests/minute per IP)
Authentication
None. Open endpoint, no key required.
Response keys
place, latitude, longitude, timezone, source, country, displayName, state (when known)
Query parameters for /location/search
Parameter
Type
Required
Default
Notes
query
string
Yes
—
The place name. Minimum 2 characters after trimming, or 400.
q
string
No
null
Alias for query, accepted because external callers commonly send ?q=. If both are present, query wins.
Comma handling is bounded at 6 segments, so a hostile many-comma query cannot trigger unbounded index scans on this public endpoint.
A miss is a 404 whose message suggests adding a country name or ISO code.
GET/location/autocomplete
Type-ahead suggestions from the same 162,000-city index.
Substring search over the local city index, for populating a birth-place picker as the user types. Much faster than an external geocoding API and free.
Rate limit
Inherits the app default (200 requests/minute per IP)
Authentication
None. Open endpoint, no key required.
Response keys
query, count, results
Query parameters for /location/autocomplete
Parameter
Type
Required
Default
Notes
query
string
Yes
—
Partial place name. Minimum 2 characters, or 400.
q
string
No
null
Alias for query.
limit
integer
No
10
Maximum results. Values above 50 are clamped to 50 rather than rejected.
Service banner: name, version and a short endpoint index.
A cheap identity check. Returns the API's own name and version string plus a hand-maintained index of its headline endpoints — useful for confirming which deployment you are talking to.
Rate limit
Inherits the app default (200 requests/minute per IP)
{
"message": "Kundli Studio Complete Horoscope API",
"version": "1.0.0",
"endpoints": {
"POST /horoscope": "Generate complete horoscope from birth details",
"POST /marriage-match": "Calculate marriage compatibility (Ashtakoota/10 Porutham)",
"GET /location/search": "Search for location and get coordinates + timezone (162K+ cities)",
"GET /location/autocomplete": "Get location suggestions for autocomplete",
"GET /docs": "Interactive API documentation",
"GET /health": "Health check endpoint"
}
}
The index here is a literal dict in the handler, not generated — it lists six entries while the service actually exposes seventeen. Treat this page or /docs as the endpoint inventory, not that field.
GET/health
Liveness probe.
Returns a fixed healthy payload. Excluded from the service's request logging so that probing it every few seconds costs nothing in log volume.
Rate limit
Inherits the app default (200 requests/minute per IP)
{ "status": "healthy", "service": "Kundli Studio API" }
GET/debug/meminfo
Operational memory observability. Not a product endpoint.
Reports the answering worker's resident set size and peak RSS from /proc, the configured allocator, and the MCP horoscope cache occupancy. It exists to watch memory behaviour under load. With multiple workers each request may land on a different one, so a single sample means little. Read-only and cheap, but treat it as an internal detail that can change without notice.
Rate limit
Inherits the app default (200 requests/minute per IP)
The rss fields read /proc and are Linux-only; off Linux the response carries an rss_error field instead.
What POST /horoscope actually returns
The response is { "birth_details": {...}, "horoscope": {...} }. The example above shows a truncated excerpt because the real payload is roughly 3.5 MB of JSON — printing it would be useless to a human and worse than useless to a model. Instead, here are all 31 top-level keys inside horoscope, in the order the engine assigns them. That is the complete shape.
calendar_info
Panchanga and calendar context for the birth moment
bhava_chart
House (bhava) cusps under the selected bhava_madhya_method
ayanamsa_value
The ayanamsa in degrees actually applied
julian_day
Julian day number of the birth moment
divisional_charts
23 vargas, D-1 to D-144, each planet with sign and longitude
nakshatra_pada
Nakshatra, pada, lord and degrees-in-nakshatra per planet
amsa_rulers
D-150 Nadiamsa amsa rulers across planets, lagnas and sphutas
yogas
Classical yoga screening
doshas
Manglik, Kaal Sarp and the other classical doshas
chara_karakas
The eight variable karakas (Atma, Amatya, …)
sahams
The 36 sahams (Arabic parts)
upagrahas
The 11 shadowy sub-planets
special_lagnas
Bhava, Hora, Ghati and the other special ascendants
house_varnadas
Varnada lagna per house
graha_arudhas
Arudha padas computed from the grahas
surya_arudhas
Arudhas measured from the Sun
chandra_arudhas
Arudhas measured from the Moon
house_relationships
Argala and Vedha between houses
planetary_states
Retrograde, combustion, dignity and related states
shad_bala
The six-fold planetary strength
bhava_bala
House strength
other_bala
Harsha, pancha and dwadhasa vargeeya bala
vimsopaka_bala
Twenty-point varga strength
vaiseshikamsa_bala
Vaiseshikamsa strength
ashtakavarga
BAV, SAV, SoAV and PAV grids
arudha_padhas
Arudha padas (note the source spelling of this key)
sphuta
The 14 sphutas
graha_dashas
Graha dasha systems, Vimshottari included
rasi_dashas
Rasi dasha systems, Chara and Narayana included
saturn_transits
Sade Sati plus 4th/8th-house Saturn transits from Moon and Lagna
longevity_prediction
Classical longevity band with the combinations that produced it
Two of these carry most of the weight. divisional_charts holds all 23 vargas keyed as D-1_rasi through D-144_dwadas_dwadasamsa, each mapping every body to a sign and a longitude. graha_dashas and rasi_dashas hold the timing systems. If you only need one of these, the MCP server has a tool per section and will not make you download the rest.
Note the spelling of arudha_padhas. It is the engine's key, not a typo on this page, and the API returns it exactly that way.
Errors
Failures come back as a JSON object with a single detail field. The message names the field and the constraint it broke, so it is worth surfacing to your users rather than swallowing.
400 Bad Request
Invalid input. A validator rejected a field. The body is {"detail": "Invalid input: <reason>"}. /location/search and /location/autocomplete also return 400 when the query is under 2 characters.
401 Unauthorized
Missing or wrong shared secret. POST /horoscope/pdf only, when the X-PDF-Secret header is absent or does not match. Fails closed: if the server has no secret configured, every request is rejected.
404 Not Found
No location matched. GET /location/search when the query resolves to nothing in the world-cities index.
422 Unprocessable Entity
Schema violation. FastAPI's own validation, raised before the handler runs — a missing required field or a wrong JSON type.
429 Too Many Requests
Rate limited. The per-endpoint limit below, or the app-wide 200/minute default, was exceeded for your IP.
500 Internal Server Error
Calculation failed. An unexpected engine error. /location/search deliberately returns a generic message here and logs the trace server-side rather than leaking internals.
A validation failure
HTTP/1.1 400 Bad Request
{ "detail": "Invalid input: 1 validation error for BirthDetailsRequest\nlatitude\n Latitude must be between -90 and 90" }
Before you build on this
There is no versioned URL prefix and no deprecation policy today. The service reports version 1.0.0 at GET / and the shapes documented here are the shapes it returns, but a breaking change would not announce itself with a new path.
There is no uptime SLA, no support contract and no status page. It is the same deployment that serves Horoscopes Today's own products.
The service returns computation, never interpretation. Nothing here decides whether a match is good or a date is auspicious — that judgement is yours, or your model's.