KP Stellar Astro API
The same deterministic KP engine the website runs on, callable from your own software. JSON in, JSON out, no SDK required.
Quick start
- Sign in and open the developer portal.
- Subscribe to developer access (₹1,999 for 30 days).
- Press Create app. You are shown an App ID and an App Secret. Copy the secret now — it is never shown again.
- Confirm the keys work before writing any real payload:
# Base URL: https://kpstellarastro.com curl https://kpstellarastro.com/api/v1/ping \ -H "X-App-Id: kpsa_app_3c5b9502b9690bbb" \ -H "X-App-Secret: kpsa_sk_YOUR_SECRET_HERE"
{ "ok": true,
"app_id": "kpsa_app_3c5b9502b9690bbb",
"expires_at": 1789181891.98 }
If that returns ok: true, your credentials are good and anything failing after this point is the payload, not the keys.
Authentication
Every /api/v1 request carries two headers. There is no OAuth flow, no token exchange, and no expiry on the credentials themselves — only on the subscription behind them.
| Header | Value |
|---|---|
X-App-Id | Your App ID, e.g. kpsa_app_3c5b9502b9690bbb |
X-App-Secret | Your App Secret, e.g. kpsa_sk_… |
Content-Type | application/json on every POST |
Check credentials
/api/v1/pingCosts nothing, computes nothing, and confirms the credentials plus how long access runs. Use it in your deploy healthcheck.
Response 200
{ "ok": true,
"app_id": "kpsa_app_3c5b9502b9690bbb",
"expires_at": 1789181891.98 // unix seconds }
Birth chart
/api/v1/birth-chartA full natal reading: planetary positions with their full KP sub-chains, twelve house cusps, dasha periods, significators, and a verdict for every life domain.
Request body
| Field | Type | Notes | |
|---|---|---|---|
birth_date | string | required | YYYY-MM-DD |
birth_time | string | required | HH:MM, 24-hour, local to the birth place |
latitude | number | required | Decimal degrees, north positive |
longitude | number | required | Decimal degrees, east positive |
place | string | optional | Echoed back; also resolves the historical time zone |
name | string | optional | Echoed back for your own labelling |
Request
curl -X POST https://kpstellarastro.com/api/v1/birth-chart \ -H "X-App-Id: $APP_ID" \ -H "X-App-Secret: $APP_SECRET" \ -H "Content-Type: application/json" \ -d '{ "name": "Asha", "birth_date": "1990-05-15", "birth_time": "10:30", "latitude": 13.0827, "longitude": 80.2707, "place": "Chennai, India" }'
Response 200 (abridged — real values)
{
"name": "Asha",
"place": "Chennai, India",
"timezone": "Asia/Kolkata",
"utc_offset_hours": 5.5,
"positions": {
"Sun": {
"name": "Sun",
"longitude": 30.485933,
"speed": 0.96426,
"retrograde": false,
"sign": "Taurus",
"sign_lord": "Venus",
"nakshatra": "Krittika",
"pada": 2,
"star_lord": "Sun",
"sub_lord": "Rahu",
"sub_sub_lord": "Ketu"
}, … 9 planets total
},
"cusps": [
{ "house": 1, "cusp": "06°58′",
"sign_lord": "Moon", "star_lord": "Saturn",
"sub_lord": "Mercury", "sub_sub_lord": "Jupiter" }
, … 12 houses total
],
"predictions": [
{
"event": "business",
"title": "Business",
"verdict": "WEAK_PROMISE",
"confidence": "WEAK",
"reasoning": "The CSL Mercury (sub lord of cusp 7) signifies
houses [3, 4, 9, 10, 11, 12], directly touching
[10, 11] the required houses [2, 7, 10, 11] …"
}, … 18 life domains total
],
"dasha": { /* Vimshottari periods */ },
"significators": [ /* per-planet A/B/C/D houses */ ],
"chart_layout": { /* wheel geometry, if you draw it */ },
"planetary_positions_table": [ … ],
"house_cusps_table": [ … ],
"cuspal_promise_table": [ … ],
"house_significators_abcd": [ … ],
"planetary_aspects": [ … ],
"vedic_details": { … },
"vedic_bhava": { /* classical Parashari graha-in-bhava */
"ascendant_sign": "Leo",
"house_system": "whole-sign (Parashari)",
"differ_count": 1, // grahas whose bhava != their KP house
"readings": [
{
"graha": "Sun", "sign": "Gemini", "degree": 0.5,
"bhava": 11, // WHOLE-SIGN house — what the reading describes
"kp_house": 10, // Placidus house, for comparison only
"houses_differ": true,
"reading": "Gains through rank and influential connections …",
"dignity": "neutral", // exalted|debilitated|moolatrikona|own|neutral
"house_nature": ["upachaya"],
"modifiers": [ /* classical rules that apply, as sentences */ ],
"karakatva": "the soul, the father, authority and vitality",
"lords": [1], // bhavas this graha RULES (depends on the lagna)
"lordship": "Sun rules your 1st (…). Sitting in the 11th, it carries
those matters into gains, income, networks …",
"node_agency": "", // Rahu/Ketu only: whose lord it acts for
"dasha": { "start": "1990-01-16", "end": "1996-01-17",
"active": false, "phase": "past" /* past|active|future */ },
"ayanamsa_sensitive": false
}, … one per graha
]
},
"doshas": { /* Kaal Sarpa + Mangal, same whole-sign houses */
"ascendant_sign": "Cancer",
"house_system": "whole-sign (Parashari)",
"mangal": {
"present": true, // decided by the LAGNA reference only — see below
"cancelled": true, // present AND at least one classical parihara applies
"severity": "mild", // none|mild|moderate
"mars_sign": "Aquarius",
"mars_bhava": 8, // WHOLE-SIGN house — what decides the verdict
"mars_kp_house": 8, // Placidus house, for comparison only
"houses_differ": false,
"houses": { "lagna": 8, "Moon": 3, "Venus": 12 },
"afflicting": ["lagna", "Venus"], // references that agree
"contested_only": false, // true = rests solely on the disputed 2nd house
"reasons": [ /* why, as sentences */ ],
"cancellations": [ /* classical parihara that apply, as sentences */ ]
},
"kaal_sarpa": {
"present": false, "partial": false,
"type_name": "Kulik", // one of the twelve, from Rahu's bhava
"rahu_bhava": 2, "ketu_bhava": 8,
"inside": [ /* grahas hemmed within the Rahu→Ketu arc */ ],
"outside": ["Moon", "Saturn"],
"on_axis": [ /* within 1° of a node — the partial (Aanshik) case */ ],
"reason": "Moon, Saturn fall outside the Rahu–Ketu arc …"
},
"remedies": [ /* only for a dosha actually found; [] otherwise */ ],
"base_rates": { "mangal_pct": 52.2, "kaal_sarpa_pct": 4.0, … }
}
}
vedic_bhava uses a different house system from the rest of this response.
Every other house number here is a KP Placidus house. Classical Parashari graha-in-bhava is read by
whole sign — the Ascendant's entire sign is the 1st bhava — and the two disagree for roughly
58% of placements (measured over 2,700). Each reading therefore carries its own bhava
alongside the kp_house, and houses_differ tells you when they part company.
Do not join these readings onto a KP house number: the sentence belongs to the whole-sign bhava.
This block is traditional correspondence, not a computed verdict, and never affects any
predictions entry.doshas follows the same whole-sign rule, and two things about it
are easy to get wrong. First, Mangal dosha is decided from the lagna alone. Counting the Moon and
Venus references as independent triggers marks 88.7% of charts Manglik; the lagna rule alone marks
52.2% (measured over 800 charts), which is what six-of-twelve houses predicts. The other references
are returned in houses/afflicting as corroboration — do not treat them as triggers.
Second, never render present without cancellations and base_rates:
about 67% of Manglik charts carry a classical cancellation, and a dosha shown without either is the
frightening half of the tradition rather than a neutral subset of it. Like vedic_bhava, this is
traditional correspondence and never affects any predictions entry.Verdict values
The verdict field on each prediction is one of a fixed set. Treat it as an enum, not as prose:
| Value | Meaning |
|---|---|
STRONGLY_PROMISED | Signified, with strong supporting significators |
PROMISED | The cuspal sub-lord signifies the required houses |
PROMISED_WITH_DELAY | Promised, but retrograde or obstructed — arrives later |
PROMISED_WITH_OBSTRUCTION | Promised against a competing signification |
WEAK_PROMISE | Thinly signified; timing is indicative only |
REQUIRES_FURTHER_TIMING_CONFIRMATION | Promise stands, timing is not yet decidable |
DENIED | Not signified. The chart does not promise it |
DENIED is not automatically bad news — for a benefic topic it means the event is not promised, but for a topic the querent does not want, denial is the good outcome. Do not render the raw enum to end users without interpreting it against the question.Horary (Prashna)
/api/v1/horaryJudges one question from the moment it is asked, using a number from 1 to 249. No birth details needed.
Request body
| Field | Type | Notes | |
|---|---|---|---|
question | string | required | One answerable question. Either/or questions are rejected |
horary_number | integer | required | 1–249 |
judgment_date | string | required | YYYY-MM-DD — the moment of asking |
judgment_time | string | required | HH:MM, local to the place below |
latitude | number | required | Where the question is asked |
longitude | number | required | |
place | string | optional | Resolves the time zone |
Request
curl -X POST https://kpstellarastro.com/api/v1/horary \ -H "X-App-Id: $APP_ID" \ -H "X-App-Secret: $APP_SECRET" \ -H "Content-Type: application/json" \ -d '{ "question": "Will I get the job?", "horary_number": 137, "judgment_date": "2026-08-13", "judgment_time": "14:20", "latitude": 13.0827, "longitude": 80.2707, "place": "Chennai, India" }'
Response 200 (abridged)
{
"question": "Will I get the job?",
"horary_number": 137,
"category": "Job / Employment",
"event_id": "job",
"primary_cusp": 6,
"required_houses": [2, 6, 10, 11],
"verdict": "PROMISED",
"confidence": "STRONG",
"reasoning": "…",
"windows": [ { "start": "…", "end": "…" } ],
"classification_confidence": "…",
"timezone": "Asia/Kolkata",
"positions": { … }, "cusps": [ … ], "significators": [ … ]
}
multi_question_notice is not an error. When the question contains more than one ask, the field is populated and you should surface it — the verdict then applies to the primary question only.Panchang
/api/v1/panchangThe five limbs for a date and place, plus the inauspicious and auspicious windows.
Request
curl -X POST https://kpstellarastro.com/api/v1/panchang \ -H "X-App-Id: $APP_ID" \ -H "X-App-Secret: $APP_SECRET" \ -H "Content-Type: application/json" \ -d '{ "date": "2026-08-13", "latitude": 13.0827, "longitude": 80.2707, "place": "Chennai, India" }'
Response 200 (real values)
{
"date": "2026-08-13",
"place": "Chennai, India",
"timezone": "Asia/Kolkata",
"utc_offset_hours": 5.5,
"vara": "Thursday",
"sunrise": "05:56",
"sunset": "18:29",
"tithi": { "index": 1, "name": "Pratipada", "paksha": "Shukla" },
"nakshatra": { "name": "…", "lord": "…" },
"yoga": { "name": "…" },
"karana": { "name": "…" },
"inauspicious": {
"rahu_kalam": { "start": "13:48", "end": "15:22" },
"yamagandam": { "start": "05:56", "end": "07:30" },
"gulika_kalam": { "start": "09:04", "end": "10:39" }
},
"auspicious": { … }
}
Compatibility
/api/v1/compatibilityAshtakoot Guna matching for two charts, scored out of 36, with each of the eight koots broken out separately.
Request body
| Field | Type | Notes | |
|---|---|---|---|
boy | object | required | A birth object, same fields as birth-chart |
girl | object | required | Likewise |
Request
curl -X POST https://kpstellarastro.com/api/v1/compatibility \ -H "X-App-Id: $APP_ID" -H "X-App-Secret: $APP_SECRET" \ -H "Content-Type: application/json" \ -d '{ "boy": { "birth_date": "1990-05-15", "birth_time": "10:30", "latitude": 13.0827, "longitude": 80.2707, "place": "Chennai, India" }, "girl": { "birth_date": "1992-08-02", "birth_time": "04:15", "latitude": 19.0760, "longitude": 72.8777, "place": "Mumbai, India" } }'
Muhurta
/api/v1/muhurta/eventsThe event ids /api/v1/muhurta accepts. Call this rather than hard-coding the list — it is engine-defined and would rot silently the first time an event is added or renamed.
Response 200
{ "events": [
{ "id": "property", "label": "Property" },
{ "id": "vehicle", "label": "Vehicle" }
, … also: foreign_travel, marriage, business, education,
higher_education, job, loan, surgery
] }
/api/v1/muhurtaAuspicious windows for a personal event, ranked, each carrying the reason it scored where it did.
| Field | Type | Notes | |
|---|---|---|---|
birth | object | required | Birth object, as above |
event_name | string | required | An id from /api/v1/muhurta/events |
max_windows | integer | optional | 1–20, default 8 |
from_date, to_date | string | optional | YYYY-MM-DD. Filters which qualifying windows come back |
viewer_utc_offset_hours | number | optional | −12 to 14. The UTC offset of the person reading the result. Defaults to the birth place's offset |
from_date in the past does not reopen this. "Today" means the reader's calendar day: send viewer_utc_offset_hours if your user may be in a different time zone from the chart's birth place, or dates that are yesterday to them can appear as today.from_date/to_date filter windows that already qualify; they do not relax the promise, confidence or Moon-transit requirements to fill an empty range. An empty result means no window qualified — present it as such rather than widening the range until something appears.TSP quick question
/api/v1/tspTheory of Short Prediction — a fast single-question read from its own 2193-segment number table. Deliberately narrower than horary, and not a substitute for it: no chart wheel is produced.
| Field | Type | Notes | |
|---|---|---|---|
tsp_number | integer | required | 1–2193 — not the 1–249 horary number |
judgment_date | string | required | YYYY-MM-DD |
judgment_time | string | required | HH:MM |
latitude, longitude | number | required | Where the question is asked |
query | string | optional | The question text, echoed back for your own labelling |
name | string | optional | Echoed back |
place | string | optional | Resolves the time zone |
query is optional and is echoed back rather than parsed — unlike horary, where the question is classified to pick the cusp. Do not infer from a TSP response that the question text was read.curl -X POST https://kpstellarastro.com/api/v1/tsp \ -H "X-App-Id: $APP_ID" -H "X-App-Secret: $APP_SECRET" \ -H "Content-Type: application/json" \ -d '{ "tsp_number": 137, "query": "Will I get the job?", "judgment_date": "2026-08-13", "judgment_time": "14:20", "latitude": 13.0827, "longitude": 80.2707, "place": "Chennai, India" }'
Cuspal interlinks
/api/v1/cuspal-interlinksKhullar's Cuspal Interlinks Theory — the star / sub / sub-sub chain linking a cusp to the houses that fulfil it. Same request body as birth-chart. This is the technique behind the "why" panel in the web app, exposed on its own.
Question cusp
/api/v1/question-cuspWhich house cusp a horary question is judged from, and which houses must be signified — the same classification horary runs internally, returned directly with no chart cast. Useful for previewing how a question will be judged before spending a horary number on it.
Request body
| Field | Type | Notes | |
|---|---|---|---|
question | string | required | Up to 2000 characters. |
in_india | boolean | optional | Default true. Disambiguates domestic vs. foreign travel questions only — has no other effect on classification. |
curl -X POST https://kpstellarastro.com/api/v1/question-cusp \ -H "X-App-Id: $APP_ID" -H "X-App-Secret: $APP_SECRET" \ -H "Content-Type: application/json" \ -d '{"question": "will I win the lottery"}'
Response 200
{ "ok": true,
"event_id": "lottery",
"category": "Lottery / Prize Bond Win",
"primary_cusp": 5,
"required_houses": [5, 9, 10, 11],
"multi_question_notice": null,
"notice_kind": null,
"doctrine": { "corroboration": "mixed", "note": "Classical texts admit more than one reading here" } }
A question that fails validation (gibberish, too short, not a real question) returns 200 with "ok": false and a message — not an error status, since asking "can this be judged?" isn't itself a failure.
Descriptive Indicators
/api/v1/descriptiveTable-lookup traits about whatever the question's cusp actually describes — a person, a place, or a matter — plus, where the event supports it, a facet reading: which of several recognised shapes (a court case settling vs. being appealed vs. a favorable judgment; a property matter being a purchase vs. a sale vs. a tenancy) the chart leans toward. Both are advisory evidence read off the cuspal sub-lord and its star lord — never a PROMISED/DENIED verdict, and never invented: a chart that shows nothing returns an empty list, which is a legitimate, common answer. Same calculation the website's own Descriptive Indicators panel uses, on the caller-supplied chart in this request rather than a signed-in account's saved one.
Request body
| Field | Type | Notes | |
|---|---|---|---|
mode | string | optional | Default "BIRTH". "HORARY" uses the horary object below instead of birth. |
question | string | required for BIRTH mode | The judged question — fixes which cusp is being described. For HORARY mode the question travels inside horary instead. |
ask | string | optional | A specific descriptive question ("what will their profession be") to filter to. Omit to get every indication the chart supports plus the list of questions that CAN be asked (can_ask). |
birth | object | required for BIRTH mode | Same shape as /api/v1/birth-chart's body. |
horary | object | required for HORARY mode | Same shape as /api/v1/horary's body. |
curl -X POST https://kpstellarastro.com/api/v1/descriptive \ -H "X-App-Id: $APP_ID" -H "X-App-Secret: $APP_SECRET" \ -H "Content-Type: application/json" \ -d '{"mode": "BIRTH", "question": "will there be a court case over the property?", "birth": {"name": "Test", "birth_date": "1990-06-15", "birth_time": "10:30", "latitude": 12.9716, "longitude": 77.5946, "place": "Bengaluru"}}'
Response 200
{ "subject": "the opposing party",
"cusp": 6,
"is_person": false,
"indications": [ ... ],
"can_ask": [ { "kind": "work", "question": "What kind of matter is this?" }, ... ],
"event": "Litigation",
"facets": [
{ "id": "settlement", "label": "settlement / compromise",
"agreement": 1, "because": "the 6th cuspal sub-lord Saturn and its star lord Sun between them signify house 7" }
] }
facets is empty for events with no defined facet table, or when the chart shows none of a facet's houses. It is a small, growing set — currently litigation, bail, property, health, foreign travel, loan, donation/charity, promotion, workplace trouble, vehicle, surgery, missing person, stock market, inheritance, gratuity/insurance, and lost property/theft recovery.
/api/v1 endpoint.Financial astrology
Four endpoints for money questions — an entity chart from a founding moment, its key windows, a head-to-head comparison of two candidate moments, and the astronomical events in a range.
/api/v1/financial/chartAn entity chart: a company from its incorporation moment, a listing, a deal. Takes birth (the moment) and event_name.
/api/v1/financial/muhurtaKey time windows for a financial event. Same body, plus optional max_windows.
/api/v1/financial/compareRank two candidate moments against each other. Takes original, candidate (each wrapping a birth object) and event_categories.
/api/v1/financial/eventsAstronomical events in a date range. Query parameters start_date and end_date, both YYYY-MM-DD.
curl "https://kpstellarastro.com/api/v1/financial/events?start_date=2026-08-01&end_date=2026-08-31" \ -H "X-App-Id: $APP_ID" -H "X-App-Secret: $APP_SECRET"
Question classification (session auth)
Part of the same developer subscription as /api/v1 above, but authenticated differently: it does not take X-App-Id / X-App-Secret at all. It uses a signed-in session bearer token instead — the same token the website itself uses — so a standalone server integration authenticating purely by App-Id/Secret cannot call it; the caller must be a signed-in account with active developer access.
/api/question/cuspWhich house cusp a horary question is judged from, and which houses must be signified — the same classification /api/horary runs internally, returned directly with no chart cast. Useful for previewing how a question will be judged before spending a horary number on it.
Auth
| Header | Value |
|---|---|
Authorization | Bearer <session token> — the same token a signed-in browser session uses, obtained via the site's own sign-in flow, not the developer portal. |
/api/v1 endpoints above (₹1,999 / 30 days) — no separate charge. A signed-in account without active developer access gets 402; there is no free or unauthenticated tier for this endpoint.Request body
| Field | Type | Notes | |
|---|---|---|---|
question | string | required | Up to 2000 characters. |
in_india | boolean | optional | Default true. Disambiguates domestic vs. foreign travel questions only — has no other effect on classification. |
curl -X POST https://kpstellarastro.com/api/question/cusp \ -H "Authorization: Bearer YOUR_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{"question": "will I win the lottery"}'
Response 200
{ "ok": true,
"event_id": "lottery",
"category": "Lottery / Prize Bond Win",
"primary_cusp": 5,
"required_houses": [5, 9, 10, 11],
"multi_question_notice": null,
"notice_kind": null,
"doctrine": { "corroboration": "mixed", "note": "Classical texts admit more than one reading here" } }
A question that fails validation (gibberish, too short, not a real question) returns 200 with "ok": false and a message, the same shape /api/question/check uses — not an error status, since asking "can this be judged?" isn't itself a failure.
What is not on the API
Three things the web app does are deliberately absent, and will stay absent until each has an answer to its own problem rather than being bolted onto this subscription:
| Not exposed | Why |
|---|---|
| Birth-time rectification (auto-search) | By far the heaviest operation on the platform — seconds per request, scoring many candidate birth times, each a full chart plus significators plus dasha. In the web app it is signed-in only and already held to roughly 4 calls/minute per account with at most 3 running concurrently site-wide. The developer tier's 60/minute is an order of magnitude beyond that, and the concurrency cap means one integration looping it would starve real users. It needs its own pricing and its own limits, not this subscription's. |
| AI explanation | Costs real money per call against a third-party model. It belongs on the credit system, not a flat monthly fee. |
| Saved charts, clients, tracked predictions | App credentials authenticate an application, not one of its end users. Serving a specific person's stored data through them would make one developer key a master key to their whole user base — that needs a per-user authorization flow, which is separate work. |
Errors
Errors are JSON with a detail string. The status code tells you which problem you have, and they are deliberately distinct — do not collapse them into one retry path.
| Status | Meaning | What to do |
|---|---|---|
401 | Invalid App ID or App Secret, or the app was revoked | Check both headers. Rotate the secret if it may have leaked. Do not retry — it will not start working |
402 | Developer access has expired | Renew in the portal. Your keys are still valid; only the subscription lapsed |
422 | The payload failed validation | Read field_errors — it names the exact field and problem |
429 | Over the rate limit | Back off and retry. See limits |
503 | The endpoint is temporarily disabled | Retry later; this is a server-side switch, not your request |
A validation error, verbatim
{
"detail": "Date is required.",
"field_errors": [
{ "field": "judgment_date", "message": "Date is required." },
{ "field": "judgment_time", "message": "Time is required." }
]
}
Rate limits
| Public endpoints (no key) | Developer API | |
|---|---|---|
| Access | Website endpoints only — no /api/v1 | All /api/v1 endpoints |
| Per minute | 10 | 60 6× more |
| Per day | 100 | 1,000 10× more |
| Counted against | Your IP, shared with everyone on the same network | Each app separately, up to 5 apps |
The per-app scope is often the bigger win: five apps at 1,000 calls each is 5,000 a day, and none of them is affected by other traffic from your network.
Limits are counted per app, not per IP, so several developers behind one office network do not throttle each other, and running your integration from a serverless platform with rotating addresses is fine. Create a separate app per environment (staging, production) to keep their budgets independent — you can have up to five.
Going over returns 429. Back off and retry; nothing is banned or charged extra.
Pricing
| Plan | Price | Includes |
|---|---|---|
| Developer access | ₹1,999 / 30 days | All /api/v1 endpoints, up to 5 apps, 1,000 calls per app per day |
Billed as a one-off 30-day period, not an auto-renewing mandate — nothing recurs without you buying it again. Renewing before expiry adds to the time you have left rather than replacing it. When the period ends, calls answer 402 and your apps are not deleted: renew and the same credentials resume working.
Notes & guarantees
- Same engine as the website. These endpoints are thin authenticated wrappers over the exact handlers the app itself calls, so the API cannot drift from what the site shows.
- Deterministic. The same input returns the same verdict. No language model is involved in any figure or judgment.
- Classification is deterministic here too. Deciding which matter a question is about (and therefore which cusp it judges from) runs on the keyword and grammar tiers only on
/api/v1— the website's language-model fallback for unusual phrasing is not applied to API calls. This keeps your results reproducible and your per-call latency predictable. A question whose wording matches no rule resolves to the general classification (11th cusp) rather than being guessed at. If you need a specific matter, name it: passlocked_event_id(for example"job_change","property_sale") on/api/v1/horaryand that classification is used directly, with no keyword matching involved. Call/api/v1/question-cuspfirst if you want to see what a question resolves to before casting a chart. - Nothing is stored from your API calls. Charts computed through
/api/v1are not saved to any account; we record only the call count and last-used time against your app. - Time zones are historical. Supplying
placeresolves the zone that was actually in force on that date, including past DST rules — this matters for a 1970s birth time. - Birth time precision. KP is minute-sensitive; the cuspal sub-lord can change within four minutes. If your users supply approximate times, present the results with that caveat.
- Versioning. Breaking changes go to a new path prefix.
/api/v1keeps its response shape.