{"openapi":"3.1.0","info":{"title":"PathFinder Public API","version":"1.0.0","description":"Machine-to-machine API for AI agents/LLM tools to obtain accurate astrological chart DATA (natal, synastry, transits, current sky) and pixel-identical rendered chart IMAGES, designed to be wrapped as an MCP server.\n\nAuthentication: `POST /v1/charts/natal`, `POST /v1/charts/transits`, and `POST /v1/charts/sky` accept requests without an API key under the documented anonymous limits. Signed image retrieval at `GET /v1/charts/img/{hash}.png` authenticates via expiring signed URLs, and `GET /v1/openapi.json` is public. Everything else requires an API key. When authenticating with an API key, send it in the `X-API-Key` header (`pf_live_<43-char base64url>`). Use the `pf_live_` key in production and the `pf_test_` key in non-production; a mismatched env tag is rejected.\n\nDATETIME CONTRACT (most common mistake): all `*DateTime` fields are LOCAL wall-clock with NO timezone offset and NO `Z` suffix (e.g. `1990-06-15T14:42:00`). The offset is derived from the accompanying `timezoneId`, which must be an IANA Tzdb id (e.g. `Europe/Amsterdam`); Windows ids like `W. Europe Standard Time` are rejected.\n\nErrors are RFC 9457 problem+json with a machine-stable `errorCode`, `retryable`, `retryAfterSeconds`, and an agent-actionable `suggestion`.\n","contact":{"name":"PathFinder","url":"https://app.pathfindercharts.com"}},"servers":[{"url":"https://public-api.pathfindercharts.com","description":"Production"}],"tags":[{"name":"Agent","description":"Agent-facing chart data and rendering endpoints. `POST /v1/charts/natal`, `POST /v1/charts/transits`, and `POST /v1/charts/sky` accept requests without an API key. Signed image retrieval at `GET /v1/charts/img/{hash}.png` authenticates via expiring signed URLs, and `GET /v1/openapi.json` is public. Everything else requires an API key.\n"}],"security":[{"ApiKey":[]}],"paths":{"/v1/charts/natal":{"post":{"tags":["Agent"],"operationId":"getNatalChart","summary":"Compute a natal (birth) chart.","description":"Returns full natal chart data: planets (sign/degree/retrograde), houses, aspects, angles (ascendant/midheaven), aspect patterns, and premium arrays including arabicParts. timeResolutions shows the exact civil-time to UTC mapping, including any DST adjustment; calcVersion identifies the engine, TZDB release, and effective aspect-orb configuration. Delegates to the same engine as the app. Cached ~1h server-side. Without X-API-Key, anonymous access is limited to 5 requests/minute and 10 successful data responses per day per observed client IP.\n","security":[{},{"ApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NatalChartRequest"},"examples":{"tropicalPlacidus":{"summary":"Tropical Placidus natal chart","value":{"birthDateTime":"1990-06-15T14:42:00","latitude":51.9244,"longitude":4.4777,"timezoneId":"Europe/Amsterdam","cityName":"Rotterdam","countryCode":"NL"}},"siderealVedic":{"summary":"Sidereal (Lahiri) Whole-Sign natal chart","value":{"birthDateTime":"1990-06-15T14:42:00","latitude":51.9244,"longitude":4.4777,"timezoneId":"Europe/Amsterdam","houseSystem":"WholeSign","ayanamsaType":"Lahiri"}}}}}},"responses":{"200":{"description":"Natal chart data.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"X-Quota-Remaining":{"$ref":"#/components/headers/QuotaRemaining"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NatalChart"}}}},"400":{"$ref":"#/components/responses/ValidationProblem"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/DuplicateRequest"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/v1/charts/archetype":{"post":{"tags":["Agent"],"operationId":"getArchetypeProfile","summary":"Compute a deterministic natal archetype profile.","description":"Computes the natal chart, planetary dominance, named archetype profile, and matching catalog definition through the shared chart engine. This endpoint performs no LLM or external service calls.\n","security":[{"ApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NatalChartRequest"},"examples":{"rotterdam":{"summary":"Archetype profile for a Rotterdam birth chart","value":{"birthDateTime":"1990-06-15T14:42:00","latitude":51.9244,"longitude":4.4777,"timezoneId":"Europe/Amsterdam","cityName":"Rotterdam","countryCode":"NL"}}}}}},"responses":{"200":{"description":"Archetype profile and matching catalog definition.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArchetypeResponse"}}}},"400":{"$ref":"#/components/responses/ValidationProblem"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/DuplicateRequest"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/v1/charts/synastry":{"post":{"tags":["Agent"],"operationId":"getSynastryChart","summary":"Compute a two-person synastry chart.","description":"Returns both natal charts, cross-aspects between the two people's planets, and a compatibility score with category scores, strongest connections, and friction points. Delegates to the same cached synastry engine as the app.\n","security":[{"ApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SynastryRequest"},"examples":{"londonParis":{"summary":"Synastry between two people born in London and Paris","value":{"personABirthDateTime":"2000-01-01T00:00:00","personALatitude":51.5074,"personALongitude":-0.1278,"personATimezoneId":"Europe/London","personAName":"Person A","personBBirthDateTime":"1990-06-15T12:00:00","personBLatitude":48.8566,"personBLongitude":2.3522,"personBTimezoneId":"Europe/Paris","personBName":"Person B","houseSystem":"Placidus"}}}}}},"responses":{"200":{"description":"Synastry chart data.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SynastryChart"}}}},"400":{"$ref":"#/components/responses/ValidationProblem"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/DuplicateRequest"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/v1/charts/transits":{"post":{"tags":["Agent"],"operationId":"getTransits","summary":"Compute a bi-wheel transit chart (requires a natal block).","description":"Returns a bi-wheel: natal positions plus transit positions plus cross-aspects. The birth fields are REQUIRED and DO affect the output (natalPlanets, natalHouses, ascendant, midheaven, transitToNatalAspects). If you only want today's sky with no birth chart, call /v1/charts/sky instead - do NOT invent a fake birth block. timeResolutions contains separate birth and transit entries. utcInstant is the resolved input; calculationInstant is the ephemeris instant and differs for converse transits. Response is a TransitChart (note: it has no arabicParts, unlike a natal chart). Without X-API-Key, anonymous access is limited to 5 requests/minute and 10 successful data responses per day per observed client IP.\n","security":[{},{"ApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransitsRequest"},"examples":{"transitsNow":{"summary":"Transits for a birth chart at a given moment","value":{"birthDateTime":"1990-06-15T14:42:00","latitude":51.9244,"longitude":4.4777,"timezoneId":"Europe/Amsterdam","transitDateTime":"2026-06-07T12:00:00","transitTimezoneId":"Europe/Amsterdam"}}}}}},"responses":{"200":{"description":"Transit (bi-wheel) chart data.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"X-Quota-Remaining":{"$ref":"#/components/headers/QuotaRemaining"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransitChart"}}}},"400":{"$ref":"#/components/responses/ValidationProblem"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/DuplicateRequest"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/v1/charts/sky":{"post":{"tags":["Agent"],"operationId":"getSkyData","summary":"Current/event sky - single wheel, minimal params.","description":"The simplest call: \"what does the sky look like at this moment?\" Requires only transitDateTime + transitTimezoneId. Returns a flat single wheel (planets + aspects). Supply latitude/longitude to also get houses/ascendant/midheaven; omit them for a pure geocentric planet+aspect sky. The response reports the selected UTC instant, offset, TZDB release, and a structured warning when the requested wall time falls in a DST gap or overlap. Without X-API-Key, anonymous access is limited to 5 requests/minute and 10 successful data responses per day per observed client IP.\n","security":[{},{"ApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkyRequest"},"examples":{"skyNow":{"summary":"Geocentric sky (no houses)","value":{"transitDateTime":"2026-06-07T12:00:00","transitTimezoneId":"Europe/Amsterdam"}},"skyWithHouses":{"summary":"Sky with houses for a location","value":{"transitDateTime":"2026-06-07T12:00:00","transitTimezoneId":"Europe/Amsterdam","latitude":51.9244,"longitude":4.4777}}}}}},"responses":{"200":{"description":"Single-wheel sky data.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"X-Quota-Remaining":{"$ref":"#/components/headers/QuotaRemaining"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkyChart"}}}},"400":{"$ref":"#/components/responses/ValidationProblem"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/DuplicateRequest"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/v1/charts/calendar":{"post":{"tags":["Agent"],"operationId":"getCalendarEvents","summary":"Find astronomical events over a date range.","description":"Returns all astronomical events (ingresses, stations, lunations, aspects, eclipses) occurring within a requested date range. Events are detected via root-bracketing and refined to 1-minute accuracy. Requires the charts:read scope. Date range is capped at 90 days; dates are interpreted in the specified timezone and converted to UTC for computation. Major aspects (conjunction, opposition, square, trine, sextile) are always included; set includeMinorAspects to true to also return semi_sextile, semi_square, quintile, sesquiquadrate, bi_quintile, and quincunx (classified as minor on this endpoint).\n","security":[{"ApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalendarEventsRequest"},"examples":{"janFeb2026":{"summary":"All events in January-February 2026","value":{"from":"2026-01-01","to":"2026-02-28","timezoneId":"Europe/Amsterdam","includeMinorAspects":false}},"janFeb2026WithMinors":{"summary":"January-February 2026 including minor aspects","value":{"from":"2026-01-01","to":"2026-02-28","timezoneId":"Europe/Amsterdam","includeMinorAspects":true}}}}}},"responses":{"200":{"description":"Astronomical events sorted by moment.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalendarEventsResponse"}}}},"400":{"$ref":"#/components/responses/ValidationProblem"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/DuplicateRequest"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/v1/charts/render":{"post":{"tags":["Agent"],"operationId":"renderChartImage","summary":"Render a pixel-identical chart PNG at a marketing size.","description":"Renders the real ChartWheel/BiWheel React component to a PNG at a Pinterest/square/ story size, using the app's exact styling. Requires the charts:render scope. Image delivery is controlled by ONE field, `delivery`: `url` (default; returns a JSON envelope with a signed image URL - use this for MCP), `bytes` (raw image/png body), or `base64` (inline, limited to ~1 MB; in practice only square fits under that cap). Do not use Accept-header or query toggles; `delivery` is the only mechanism.\n","security":[{"ApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RenderRequest"},"examples":{"skyPin":{"summary":"Pinterest pin of today's sky","value":{"chartKind":"sky","chart":{"transitDateTime":"2026-06-07T12:00:00","transitTimezoneId":"Europe/Amsterdam"},"format":"pinterest","theme":"dark","showDetails":true,"name":"Sky of June 7, 2026"}},"natalSquareBytes":{"summary":"Square natal render returned as raw bytes","value":{"chartKind":"natal","chart":{"birthDateTime":"1990-06-15T14:42:00","latitude":51.9244,"longitude":4.4777,"timezoneId":"Europe/Amsterdam"},"format":"square","delivery":"bytes"}}}}}},"responses":{"200":{"description":"Rendered image. With delivery=url or base64, an application/json envelope; with delivery=bytes, the raw image/png body with an immutable Cache-Control and ETag.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RenderResult"},"examples":{"urlEnvelope":{"value":{"format":"pinterest","width":2000,"height":3000,"contentType":"image/png","byteSize":412233,"url":"https://public-api.pathfindercharts.com/v1/charts/img/4f3c0b9e1a2d3c4e5f60718293a4b5c6d7e8f90112233445566778899aabbccdd.png?exp=1717761600&sig=abc123","expiresAt":"2026-06-07T13:00:00Z","cacheHit":true}}}},"image/png":{"schema":{"type":"string","format":"binary"}}}},"400":{"$ref":"#/components/responses/ValidationProblem"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/DuplicateRequest"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/RendererUnavailable"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/v1/charts/img/{hash}.png":{"get":{"tags":["Agent"],"operationId":"getRenderedImage","summary":"Fetch a previously rendered, content-addressed image.","description":"Serves an immutable, content-addressed PNG produced by renderChartImage. URLs are signed (exp + sig query params) and unguessable from birth data; expired or invalid signatures are rejected. `hash` must be 64 lowercase hex chars.\n","security":[],"parameters":[{"name":"hash","in":"path","required":true,"schema":{"type":"string","pattern":"^[a-f0-9]{64}$"},"description":"The 64-char hex content hash of the render."},{"name":"exp","in":"query","required":true,"schema":{"type":"integer","format":"int64"},"description":"Unix expiry timestamp embedded in the signed URL."},{"name":"sig","in":"query","required":true,"schema":{"type":"string"},"description":"URL signature (HMAC of hash|exp with a server secret)."}],"responses":{"200":{"description":"The PNG image.","headers":{"ETag":{"schema":{"type":"string"}},"Cache-Control":{"schema":{"type":"string"},"example":"public, max-age=31536000, immutable"}},"content":{"image/png":{"schema":{"type":"string","format":"binary"}}}},"403":{"$ref":"#/components/responses/InvalidSignature"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/openapi.json":{"get":{"tags":["Agent"],"operationId":"getOpenApi","summary":"This OpenAPI 3.1 document.","description":"Read-only, production-safe (no UI). Source of truth for MCP tool generation.","security":[],"responses":{"200":{"description":"The OpenAPI 3.1 document.","content":{"application/json":{"schema":{"type":"object"}}}}}}}},"components":{"securitySchemes":{"ApiKey":{"type":"apiKey","in":"header","name":"X-API-Key","description":"API key in the form pf_live_<43-char base64url> (prod) or pf_test_<...> (non-prod). Stored hashed (HMAC-SHA256 + pepper) server-side.\n"}},"headers":{"RateLimitLimit":{"description":"Maximum requests admitted per minute for the authenticated key or anonymous IP identity.","schema":{"type":"integer","minimum":1}},"RateLimitRemaining":{"description":"Requests remaining in the current rate-limit window.","schema":{"type":"integer","minimum":0}},"RateLimitReset":{"description":"Seconds until the current rate-limit window resets.","schema":{"type":"integer","minimum":1}},"QuotaRemaining":{"description":"Successful data responses remaining in the current UTC-day quota.","schema":{"type":"integer","minimum":0}}},"responses":{"Unauthorized":{"description":"Missing/invalid/revoked/expired key or env-tag mismatch.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"example":{"type":"https://public-api.pathfindercharts.com/problems/invalid_api_key","title":"Invalid API key","status":401,"detail":"API key is missing, invalid, revoked, or for the wrong environment.","errorCode":"invalid_api_key","retryable":false,"suggestion":"Check X-API-Key; ensure it's the pf_live_ key for this env and not revoked."}}}},"Forbidden":{"description":"Authenticated but lacking the required scope.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"example":{"type":"https://public-api.pathfindercharts.com/problems/insufficient_scope","title":"Insufficient scope","status":403,"detail":"This key lacks a scope required by this endpoint.","errorCode":"insufficient_scope","retryable":false,"suggestion":"Request a key with the scope required by this endpoint."}}}},"InvalidSignature":{"description":"Expired or invalid signed-image URL.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"example":{"type":"https://public-api.pathfindercharts.com/problems/invalid_signature","title":"Invalid signature","status":403,"detail":"Expired or invalid image signature.","errorCode":"invalid_signature","retryable":false,"suggestion":"The signed image URL is expired or invalid; request a fresh one via renderChartImage."}}}},"NotFound":{"description":"Resource not found (e.g. unknown or malformed image hash).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"example":{"type":"https://public-api.pathfindercharts.com/problems/not_found","title":"Not found","status":404,"errorCode":"not_found","retryable":false,"suggestion":"No image for that hash (expired or never rendered)."}}}},"ValidationProblem":{"description":"Request failed validation.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validationFailed":{"value":{"type":"https://public-api.pathfindercharts.com/problems/validation_failed","title":"Validation failed","status":400,"detail":"One or more fields are invalid.","errorCode":"validation_failed","retryable":false,"suggestion":"Fix the fields listed in `errors` and resend.","errors":{"latitude":["Latitude must be between -90 and 90."]}}},"invalidLocalDatetime":{"value":{"type":"https://public-api.pathfindercharts.com/problems/invalid_local_datetime","title":"Invalid local datetime","status":400,"detail":"birthDateTime must be a local wall-clock value with no offset or Z.","errorCode":"invalid_local_datetime","retryable":false,"suggestion":"Send datetimes as local wall-clock with NO offset/Z; set the zone via timezoneId."}}}}}},"RateLimited":{"description":"Per-minute rate limit or daily quota exceeded.","headers":{"Retry-After":{"schema":{"type":"integer"}}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rateLimited":{"value":{"type":"https://public-api.pathfindercharts.com/problems/rate_limited","title":"Rate limited","status":429,"errorCode":"rate_limited","retryable":true,"retryAfterSeconds":12,"suggestion":"Per-minute limit hit; back off retryAfterSeconds."}},"quotaExceeded":{"value":{"type":"https://public-api.pathfindercharts.com/problems/quota_exceeded","title":"Quota exceeded","status":429,"errorCode":"quota_exceeded","retryable":true,"retryAfterSeconds":3600,"suggestion":"Daily quota exhausted; do NOT retry until reset. Other kinds remain available."}}}}}},"RendererUnavailable":{"description":"Renderer saturated or timed out.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"example":{"type":"https://public-api.pathfindercharts.com/problems/renderer_unavailable","title":"Renderer unavailable","status":503,"errorCode":"renderer_unavailable","retryable":true,"retryAfterSeconds":5,"suggestion":"Renderer saturated/timed out; retry after retryAfterSeconds with backoff."}}}},"InternalError":{"description":"Unexpected server error.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"example":{"type":"https://public-api.pathfindercharts.com/problems/internal_error","title":"Internal server error","status":500,"errorCode":"internal_error","retryable":false,"suggestion":"Unexpected server error; do not retry blindly."}}}},"DuplicateRequest":{"description":"The X-Request-Id was already processed successfully (idempotency replay guard).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"example":{"type":"https://public-api.pathfindercharts.com/problems/duplicate_request","title":"Duplicate request","status":409,"errorCode":"duplicate_request","retryable":false,"suggestion":"Use a fresh X-Request-Id for a new operation; this id was already processed."}}}}},"schemas":{"ProblemDetails":{"type":"object","description":"RFC 9457 problem+json with agent-friendly extensions.","properties":{"type":{"type":"string","format":"uri"},"title":{"type":"string"},"status":{"type":"integer"},"detail":{"type":"string"},"instance":{"type":"string"},"errorCode":{"type":"string","enum":["invalid_api_key","insufficient_scope","invalid_signature","validation_failed","invalid_local_datetime","payload_too_large","rate_limited","quota_exceeded","duplicate_request","renderer_unavailable","not_found","internal_error"]},"retryable":{"type":"boolean"},"retryAfterSeconds":{"type":["integer","null"]},"suggestion":{"type":"string"},"errors":{"type":["object","null"],"additionalProperties":{"type":"array","items":{"type":"string"}}}},"required":["title","status","errorCode","retryable"]},"HouseSystem":{"type":"string","enum":["Placidus","WholeSign","Equal","Koch","Regiomontanus","Campanus","Porphyry"]},"AyanamsaType":{"type":"string","enum":["None","Lahiri","FaganBradley","Raman","Krishnamurti"],"description":"None = tropical zodiac (default)."},"Direction":{"type":"string","enum":["Direct","Converse"]},"Planet":{"type":"string","enum":["Sun","Moon","Mercury","Venus","Mars","Jupiter","Saturn","Uranus","Neptune","Pluto","Chiron","NorthNode","SouthNode","Lilith"]},"ZodiacSign":{"type":"string","enum":["Aries","Taurus","Gemini","Cancer","Leo","Virgo","Libra","Scorpio","Sagittarius","Capricorn","Aquarius","Pisces"]},"AspectType":{"type":"string","enum":["Conjunction","Sextile","Square","Trine","Opposition","SemiSextile","SemiSquare","Sesquiquadrate","Quincunx","Quintile","BiQuintile"]},"AspectApplicability":{"type":"string","enum":["Applying","Separating","Exact"]},"PatternType":{"type":"string","enum":["GrandTrine","TSquare","GrandCross","Yod","Kite","Stellium","MysticRectangle","Cradle"]},"AspectOrbConfig":{"type":"object","description":"Aspect orb thresholds in degrees. Each value must be within [0,15] and luminaryOrbBonus within [0,4]; out-of-range values are rejected with validation_failed (not clamped).","properties":{"conjunctionOrb":{"type":"number","default":8},"oppositionOrb":{"type":"number","default":8},"trineOrb":{"type":"number","default":8},"squareOrb":{"type":"number","default":7},"sextileOrb":{"type":"number","default":6},"semiSextileOrb":{"type":"number","default":2},"semiSquareOrb":{"type":"number","default":2},"sesquiquadrateOrb":{"type":"number","default":2},"quincunxOrb":{"type":"number","default":3},"quintileOrb":{"type":"number","default":2},"biQuintileOrb":{"type":"number","default":2},"luminaryOrbBonus":{"type":"number","default":2}}},"NatalChartRequest":{"type":"object","required":["birthDateTime","latitude","longitude","timezoneId"],"properties":{"birthDateTime":{"type":"string","description":"Local wall-clock birth time, NO offset/Z (e.g. 1990-06-15T14:42:00). Year >= 1800; not in the future.","example":"1990-06-15T14:42:00"},"birthTimeKnown":{"type":"boolean","default":true,"description":"Whether the local birth time is known. False uses noon for planetary positions and omits time-dependent claims."},"latitude":{"type":"number","minimum":-90,"maximum":90},"longitude":{"type":"number","minimum":-180,"maximum":180},"timezoneId":{"type":"string","description":"IANA Tzdb id (e.g. Europe/Amsterdam). Windows ids are rejected.","example":"Europe/Amsterdam"},"cityName":{"type":["string","null"],"maxLength":60,"description":"Display label only; no control chars or URLs."},"countryCode":{"type":["string","null"],"maxLength":8},"houseSystem":{"$ref":"#/components/schemas/HouseSystem","default":"Placidus"},"orbConfig":{"$ref":"#/components/schemas/AspectOrbConfig"},"ayanamsaType":{"$ref":"#/components/schemas/AyanamsaType","default":"None"}}},"ArchetypeResponse":{"type":"object","properties":{"profile":{"$ref":"#/components/schemas/ArchetypeProfile"},"definition":{"$ref":"#/components/schemas/ArchetypeDefinition"}},"required":["profile","definition"]},"ArchetypeProfile":{"type":"object","properties":{"name":{"type":"string"},"principle":{"type":"string"},"isPairArchetype":{"type":"boolean"},"primaryPlanet":{"$ref":"#/components/schemas/Planet"},"secondaryPlanet":{"oneOf":[{"$ref":"#/components/schemas/Planet"},{"type":"null"}]},"primaryConnectionModifier":{"$ref":"#/components/schemas/ConnectionModifier"},"knownFor":{"oneOf":[{"$ref":"#/components/schemas/KnownForTrait"},{"type":"null"}]}},"required":["name","principle","isPairArchetype","primaryPlanet","primaryConnectionModifier","knownFor"]},"ArchetypeDefinition":{"type":"object","properties":{"name":{"type":"string"},"principle":{"type":"string"},"drive":{"type":"string"},"strengths":{"type":"string"},"shadow":{"type":"string"},"dynamics":{"type":["string","null"]}},"required":["name","principle","drive","strengths","shadow"]},"ConnectionModifier":{"type":"object","properties":{"primaryName":{"type":"string","enum":["ASC","MC","Sun","Moon",""]},"domain":{"type":"string"},"visibility":{"type":"string"},"quality":{"type":"string"}},"required":["primaryName","domain","visibility","quality"]},"KnownForTrait":{"type":"object","properties":{"planet":{"$ref":"#/components/schemas/Planet"},"label":{"type":"string"}},"required":["planet","label"]},"SynastryRequest":{"type":"object","required":["personABirthDateTime","personALatitude","personALongitude","personATimezoneId","personBBirthDateTime","personBLatitude","personBLongitude","personBTimezoneId"],"properties":{"personABirthDateTime":{"type":"string","description":"Local wall-clock birth time for person A, NO offset/Z. Year >= 1800; not in the future.","example":"2000-01-01T00:00:00"},"personALatitude":{"type":"number","minimum":-90,"maximum":90},"personALongitude":{"type":"number","minimum":-180,"maximum":180},"personATimezoneId":{"type":"string","example":"Europe/London"},"personAName":{"type":["string","null"]},"personBBirthDateTime":{"type":"string","description":"Local wall-clock birth time for person B, NO offset/Z. Year >= 1800; not in the future.","example":"1990-06-15T12:00:00"},"personBLatitude":{"type":"number","minimum":-90,"maximum":90},"personBLongitude":{"type":"number","minimum":-180,"maximum":180},"personBTimezoneId":{"type":"string","example":"Europe/Paris"},"personBName":{"type":["string","null"]},"houseSystem":{"$ref":"#/components/schemas/HouseSystem","default":"Placidus"},"orbConfig":{"$ref":"#/components/schemas/AspectOrbConfig"},"ayanamsaType":{"$ref":"#/components/schemas/AyanamsaType","default":"None"}}},"TransitsRequest":{"type":"object","required":["birthDateTime","latitude","longitude","timezoneId","transitDateTime","transitTimezoneId"],"properties":{"birthDateTime":{"type":"string","description":"Local wall-clock birth time, NO offset/Z. Year >= 1800; not in future. Affects the natal half of the bi-wheel.","example":"1990-06-15T14:42:00"},"latitude":{"type":"number","minimum":-90,"maximum":90},"longitude":{"type":"number","minimum":-180,"maximum":180},"timezoneId":{"type":"string","example":"Europe/Amsterdam"},"cityName":{"type":["string","null"],"maxLength":60},"countryCode":{"type":["string","null"],"maxLength":8},"transitDateTime":{"type":"string","description":"Local wall-clock transit moment, NO offset/Z. Year >= 1800 and <= now + 10 years.","example":"2026-06-07T12:00:00"},"transitTimezoneId":{"type":"string","example":"Europe/Amsterdam"},"direction":{"$ref":"#/components/schemas/Direction","default":"Direct"},"houseSystem":{"$ref":"#/components/schemas/HouseSystem","default":"Placidus"},"orbConfig":{"$ref":"#/components/schemas/AspectOrbConfig"},"ayanamsaType":{"$ref":"#/components/schemas/AyanamsaType","default":"None"}}},"SkyRequest":{"type":"object","required":["transitDateTime","transitTimezoneId"],"properties":{"transitDateTime":{"type":"string","description":"Local wall-clock sky moment, NO offset/Z. Year >= 1800 and <= now + 10 years.","example":"2026-06-07T12:00:00"},"transitTimezoneId":{"type":"string","example":"Europe/Amsterdam"},"latitude":{"type":["number","null"],"minimum":-90,"maximum":90,"description":"Optional. Omit for a pure geocentric sky (no houses/angles)."},"longitude":{"type":["number","null"],"minimum":-180,"maximum":180,"description":"Required iff latitude is supplied."},"houseSystem":{"$ref":"#/components/schemas/HouseSystem","default":"WholeSign"},"orbConfig":{"$ref":"#/components/schemas/AspectOrbConfig"},"ayanamsaType":{"$ref":"#/components/schemas/AyanamsaType","default":"None"}}},"RenderRequest":{"type":"object","required":["chart"],"properties":{"chartKind":{"type":"string","enum":["natal","transit","sky"],"default":"natal","description":"Selects the chart data type and the component (ChartWheel for natal/sky, BiWheel for transit)."},"chart":{"description":"The request payload matching chartKind (NatalChartRequest, TransitsRequest, or SkyRequest). Validated identically to the data endpoints.","oneOf":[{"$ref":"#/components/schemas/NatalChartRequest"},{"$ref":"#/components/schemas/TransitsRequest"},{"$ref":"#/components/schemas/SkyRequest"}]},"format":{"type":"string","enum":["pinterest","square","story"],"default":"pinterest","description":"pinterest=2000x3000, square=1080x1080, story=1080x1920."},"theme":{"type":"string","enum":["dark","light"],"default":"dark","description":"dark is the app default; light maps to html.light."},"delivery":{"type":"string","enum":["url","bytes","base64"],"default":"url","description":"url=JSON envelope w/ signed image URL (use for MCP); bytes=raw image/png; base64=inline (<=1MB, square in practice)."},"showDetails":{"type":"boolean","default":false,"description":"Draw the details overlay (name + Sun/Moon/ASC line)."},"name":{"type":["string","null"],"maxLength":60,"description":"Overlay title. No control chars or URLs; HTML-escaped. If showDetails=true and name is empty, the name line is omitted."},"display":{"type":"object","description":"Render-time display controls: filter which aspects/patterns the wheel shows and control center visibility, focus emphasis, and explicit planet dimming. Every field is optional; an absent block draws every computed aspect, shows every detected pattern and the center medallion, and applies no emphasis or dimming.\n","properties":{"aspects":{"type":"object","description":"Aspect filter. Omitted sub-fields apply no filter.","properties":{"types":{"type":"array","items":{"$ref":"#/components/schemas/AspectType"},"description":"Whitelist of aspect types to keep; omit/empty to keep all types."},"maxOrb":{"type":"number","exclusiveMinimum":0,"maximum":15,"description":"Extra orb ceiling in degrees; omit for no extra cap."},"involving":{"type":"array","items":{"$ref":"#/components/schemas/Planet"},"description":"Keep only aspects touching one of these planets; omit to keep all."},"pairs":{"type":"array","description":"Exact aspect whitelist; planet order is ignored. Available for all chart kinds; omit/empty for no pair filter.","items":{"type":"object","required":["planet1","planet2","type"],"properties":{"planet1":{"$ref":"#/components/schemas/Planet"},"planet2":{"$ref":"#/components/schemas/Planet"},"type":{"$ref":"#/components/schemas/AspectType"}}}}}},"patterns":{"type":"object","description":"Pattern overlay control.","properties":{"show":{"type":"boolean","default":true,"description":"false hides the pattern overlay entirely."},"only":{"type":"array","items":{"$ref":"#/components/schemas/PatternType"},"description":"Whitelist of pattern types; omit to show all detected patterns."}}},"center":{"type":"object","description":"Center medallion visibility control.","properties":{"show":{"type":"boolean","default":true,"description":"false hides the center medallion, including the chart-kind label."}}},"focus":{"description":"Emphasize AT MOST ONE of a pattern, a single aspect, or a planet list.","oneOf":[{"type":"object","required":["pattern"],"properties":{"pattern":{"$ref":"#/components/schemas/PatternType"}}},{"type":"object","required":["aspect"],"properties":{"aspect":{"type":"object","required":["planet1","planet2","type"],"properties":{"planet1":{"$ref":"#/components/schemas/Planet"},"planet2":{"$ref":"#/components/schemas/Planet"},"type":{"$ref":"#/components/schemas/AspectType"}}}}},{"type":"object","required":["planets"],"properties":{"planets":{"type":"array","items":{"$ref":"#/components/schemas/Planet"},"description":"Emphasize these planets; natal/sky only — 400 on transit."}}}]},"dim":{"type":"object","description":"Planet de-emphasis. May coexist with focus; dim wins on overlap. Natal/sky only — 400 on transit.","properties":{"planets":{"type":"array","items":{"$ref":"#/components/schemas/Planet"},"description":"Dim these planet glyphs and their aspect lines; omit/empty for none."}}}}},"background":{"type":"object","nullable":true,"description":"Optional background image for composite rendering. The wheel renders directly onto this background. Absent/null means current behavior (wheel on solid theme color). INTERNAL tier only.\n","properties":{"dataBase64":{"type":"string","description":"Base64-encoded PNG or JPEG image bytes (required if background present)."},"fit":{"type":"string","enum":["cover","contain"],"default":"cover","description":"cover: scale to fill the frame (may crop); contain: scale to fit inside."},"wheelScale":{"type":"number","minimum":0.1,"maximum":1,"default":0.88,"description":"Wheel width as a fraction of frame width."},"scrim":{"type":"number","minimum":0,"maximum":1,"default":0,"description":"Dark veil opacity between background and wheel for legibility."}}}}},"RenderResult":{"type":"object","description":"Returned for delivery=url (with `url`) or delivery=base64 (with `dataBase64`).","properties":{"format":{"type":"string","enum":["pinterest","square","story"]},"width":{"type":"integer"},"height":{"type":"integer"},"contentType":{"type":"string","example":"image/png"},"byteSize":{"type":"integer"},"url":{"type":["string","null"],"format":"uri","description":"Signed image URL (delivery=url)."},"dataBase64":{"type":["string","null"],"description":"Base64 PNG (delivery=base64)."},"expiresAt":{"type":["string","null"],"format":"date-time"},"cacheHit":{"type":"boolean"}},"required":["format","width","height","contentType","byteSize","cacheHit"]},"EclipticPosition":{"type":"object","properties":{"longitude":{"type":"number","description":"Ecliptic longitude 0-360 degrees."},"latitude":{"type":"number","description":"Ecliptic latitude -90..+90 degrees."},"distance":{"type":"number","description":"Distance from Earth (AU)."},"sign":{"$ref":"#/components/schemas/ZodiacSign"},"degreeInSign":{"type":"number"},"degrees":{"type":"integer"},"minutes":{"type":"integer"},"seconds":{"type":"integer"}}},"PlanetPosition":{"type":"object","properties":{"planet":{"$ref":"#/components/schemas/Planet"},"position":{"$ref":"#/components/schemas/EclipticPosition"},"dailyMotion":{"type":"number","description":"Degrees/day; negative = retrograde."},"isRetrograde":{"type":"boolean"}}},"HouseCusp":{"type":"object","properties":{"houseNumber":{"type":"integer","minimum":1,"maximum":12},"cuspPosition":{"$ref":"#/components/schemas/EclipticPosition"}}},"Aspect":{"type":"object","properties":{"planet1":{"$ref":"#/components/schemas/Planet"},"planet2":{"$ref":"#/components/schemas/Planet"},"type":{"$ref":"#/components/schemas/AspectType"},"orb":{"type":"number"},"exactAngle":{"type":"number"},"applicability":{"$ref":"#/components/schemas/AspectApplicability"}}},"AngleAspect":{"type":"object","properties":{"planet":{"$ref":"#/components/schemas/Planet"},"angleName":{"type":"string","enum":["ASC","DSC","MC","IC"]},"type":{"$ref":"#/components/schemas/AspectType"},"orb":{"type":"number"},"exactAngle":{"type":"number"},"applicability":{"$ref":"#/components/schemas/AspectApplicability"}}},"TransitDeclinationAspect":{"type":"object","description":"A role-preserving declination aspect from a transiting planet to a natal planet.","properties":{"transitingPlanet":{"$ref":"#/components/schemas/Planet"},"transitingDeclination":{"type":"number"},"natalPlanet":{"$ref":"#/components/schemas/Planet"},"natalDeclination":{"type":"number"},"isParallel":{"type":"boolean"},"orb":{"type":"number"}},"required":["transitingPlanet","transitingDeclination","natalPlanet","natalDeclination","isParallel","orb"]},"ChartPointRole":{"type":"string","enum":["Natal","Transit"]},"ChartPointIdentity":{"type":"object","properties":{"planet":{"$ref":"#/components/schemas/Planet"},"role":{"$ref":"#/components/schemas/ChartPointRole"}},"required":["planet","role"]},"CrossChartAspect":{"type":"object","properties":{"point1":{"$ref":"#/components/schemas/ChartPointIdentity"},"point2":{"$ref":"#/components/schemas/ChartPointIdentity"},"type":{"$ref":"#/components/schemas/AspectType"},"orb":{"type":"number"},"exactAngle":{"type":"number"},"applicability":{"$ref":"#/components/schemas/AspectApplicability"}},"required":["point1","point2","type","orb","exactAngle","applicability"]},"CrossChartAspectPattern":{"type":"object","properties":{"patternType":{"$ref":"#/components/schemas/PatternType"},"involvedPoints":{"type":"array","items":{"$ref":"#/components/schemas/ChartPointIdentity"}},"formingAspects":{"type":"array","items":{"$ref":"#/components/schemas/CrossChartAspect"}},"apexPoint":{"oneOf":[{"$ref":"#/components/schemas/ChartPointIdentity"},{"type":"null"}]}},"required":["patternType","involvedPoints","formingAspects"]},"AspectPattern":{"type":"object","description":"A detected geometric pattern (Grand Trine, T-Square, etc.). Shape is engine-defined.","additionalProperties":true},"GeoLocation":{"type":"object","properties":{"latitude":{"type":"number"},"longitude":{"type":"number"},"timezoneId":{"type":"string"},"cityName":{"type":["string","null"]},"countryCode":{"type":["string","null"]}}},"TimeResolutionWarning":{"type":"object","description":"Structured decision made while resolving a skipped or ambiguous local wall time.","properties":{"code":{"type":"string","enum":["dst_gap_adjusted","dst_overlap_resolved"],"example":"dst_overlap_resolved"},"resolution":{"type":"string","enum":["shiftedForward","earlierOccurrence"],"example":"earlierOccurrence"},"requestedLocalDateTime":{"type":"string","description":"Local wall time supplied by the caller, without an offset.","example":"2025-10-26T02:30:00"},"resolvedLocalDateTime":{"type":"string","description":"Local wall time represented by the selected instant after any gap adjustment.","example":"2025-10-26T02:30:00"},"selectedOffset":{"type":"string","description":"UTC offset selected by the lenient resolver.","example":"+02"},"candidateOffsets":{"type":"array","description":"Offsets on both sides of the transition, in earlier-to-later order.","items":{"type":"string"},"example":["+02","+01"]}},"required":["code","resolution","requestedLocalDateTime","resolvedLocalDateTime","selectedOffset","candidateOffsets"]},"ChartTimeResolution":{"type":"object","description":"Auditable mapping from one semantic chart-time input to the ephemeris instant.","properties":{"role":{"type":"string","enum":["birth","transit","sky"],"example":"transit"},"inputLocalDateTime":{"type":["string","null"],"description":"Caller-supplied civil time; null when the request supplied a UTC instant.","example":"2025-10-26T02:30:00"},"resolvedLocalDateTime":{"type":"string","description":"Local wall time corresponding to the selected UTC instant.","example":"2025-10-26T02:30:00"},"resolvedTimeZoneId":{"type":"string","description":"IANA TZDB zone used for the resolution.","example":"Europe/Amsterdam"},"appliedOffset":{"type":"string","description":"UTC offset in force at the selected instant.","example":"+02"},"utcInstant":{"type":"string","format":"date-time","description":"UTC instant obtained by resolving the caller's input.","example":"2025-10-26T00:30:00Z"},"calculationInstant":{"type":"string","format":"date-time","description":"UTC instant evaluated by the ephemeris; differs from utcInstant for converse calculations.","example":"2025-10-26T00:30:00Z"},"tzdbVersion":{"type":"string","description":"TZDB release identifier used for zone rules.","example":"TZDB: 2025b (mapping: $Revision$)"},"warnings":{"type":"array","items":{"$ref":"#/components/schemas/TimeResolutionWarning"}}},"required":["role","resolvedLocalDateTime","resolvedTimeZoneId","appliedOffset","utcInstant","calculationInstant","tzdbVersion","warnings"]},"NatalChart":{"type":"object","description":"Complete natal chart (note arabicParts present here, absent on TransitChart).","properties":{"timeResolutions":{"type":"array","items":{"$ref":"#/components/schemas/ChartTimeResolution"}},"calcVersion":{"type":"string","description":"Deterministic fingerprint of chart-engine revision, TZDB release, and effective aspect orbs."},"birthMoment":{"type":"string","format":"date-time","description":"UTC instant of birth."},"birthLocal":{"type":"string","description":"Local birth time (no offset)."},"birthLocation":{"$ref":"#/components/schemas/GeoLocation"},"planets":{"type":"array","items":{"$ref":"#/components/schemas/PlanetPosition"}},"houses":{"type":"array","items":{"$ref":"#/components/schemas/HouseCusp"}},"houseSystem":{"$ref":"#/components/schemas/HouseSystem"},"aspects":{"type":"array","items":{"$ref":"#/components/schemas/Aspect"}},"ascendant":{"$ref":"#/components/schemas/EclipticPosition"},"midheaven":{"$ref":"#/components/schemas/EclipticPosition"},"patterns":{"type":"array","items":{"$ref":"#/components/schemas/AspectPattern"}},"angleAspects":{"type":"array","items":{"$ref":"#/components/schemas/AngleAspect"}},"ayanamsaType":{"$ref":"#/components/schemas/AyanamsaType"},"fixedStarConjunctions":{"type":"array","items":{"type":"object","additionalProperties":true}},"midpointActivations":{"type":"array","items":{"type":"object","additionalProperties":true}},"arabicParts":{"type":"array","items":{"type":"object","additionalProperties":true}},"declinations":{"type":"array","items":{"type":"object","additionalProperties":true}},"declinationAspects":{"type":"array","items":{"type":"object","additionalProperties":true}}},"required":["timeResolutions","calcVersion","birthMoment","birthLocal","birthLocation","planets","houses","houseSystem","aspects","ascendant","midheaven"]},"ScoredConnection":{"type":"object","properties":{"planet1":{"$ref":"#/components/schemas/Planet"},"planet2":{"$ref":"#/components/schemas/Planet"},"aspectType":{"$ref":"#/components/schemas/AspectType"},"score":{"type":"number"},"description":{"type":"string"}},"required":["planet1","planet2","aspectType","score","description"]},"FrictionPoint":{"type":"object","properties":{"planet1":{"$ref":"#/components/schemas/Planet"},"planet2":{"$ref":"#/components/schemas/Planet"},"aspectType":{"$ref":"#/components/schemas/AspectType"},"score":{"type":"number"},"description":{"type":"string"}},"required":["planet1","planet2","aspectType","score","description"]},"CompatibilityScore":{"type":"object","properties":{"overallScore":{"type":"number","minimum":0,"maximum":100},"categoryScores":{"type":"object","additionalProperties":{"type":"number","minimum":0,"maximum":100}},"topConnections":{"type":"array","items":{"$ref":"#/components/schemas/ScoredConnection"}},"frictionPoints":{"type":"array","items":{"$ref":"#/components/schemas/FrictionPoint"}}},"required":["overallScore","categoryScores","topConnections","frictionPoints"]},"SynastryChart":{"type":"object","description":"Two natal charts with cross-aspects and computed compatibility.","properties":{"chartA":{"$ref":"#/components/schemas/NatalChart"},"chartB":{"$ref":"#/components/schemas/NatalChart"},"crossAspects":{"type":"array","items":{"$ref":"#/components/schemas/Aspect"}},"personAName":{"type":["string","null"]},"personBName":{"type":["string","null"]},"compatibility":{"oneOf":[{"$ref":"#/components/schemas/CompatibilityScore"},{"type":"null"}]},"composite":{"oneOf":[{"$ref":"#/components/schemas/NatalChart"},{"type":"null"}]}},"required":["chartA","chartB","crossAspects"]},"TransitChart":{"type":"object","description":"Bi-wheel transit chart (no arabicParts).","properties":{"timeResolutions":{"type":"array","items":{"$ref":"#/components/schemas/ChartTimeResolution"}},"calcVersion":{"type":"string","description":"Deterministic fingerprint of chart-engine revision, TZDB release, and effective aspect orbs."},"transitMoment":{"type":"string","format":"date-time","description":"UTC instant of the requested transit moment."},"natalLocation":{"$ref":"#/components/schemas/GeoLocation"},"natalPlanets":{"type":"array","items":{"$ref":"#/components/schemas/PlanetPosition"}},"natalHouses":{"type":"array","items":{"$ref":"#/components/schemas/HouseCusp"}},"houseSystem":{"$ref":"#/components/schemas/HouseSystem"},"ascendant":{"$ref":"#/components/schemas/EclipticPosition"},"midheaven":{"$ref":"#/components/schemas/EclipticPosition"},"transitPlanets":{"type":"array","items":{"$ref":"#/components/schemas/PlanetPosition"}},"transitToNatalAspects":{"type":"array","items":{"$ref":"#/components/schemas/Aspect"},"description":"Cross-aspects; Planet1 = transit planet, Planet2 = natal planet."},"transitAspects":{"type":"array","items":{"$ref":"#/components/schemas/Aspect"}},"natalAspects":{"type":"array","items":{"$ref":"#/components/schemas/Aspect"}},"angleAspects":{"type":"array","items":{"$ref":"#/components/schemas/AngleAspect"}},"ayanamsaType":{"$ref":"#/components/schemas/AyanamsaType"},"patterns":{"type":"array","items":{"$ref":"#/components/schemas/AspectPattern"}},"crossChartPatterns":{"type":"array","items":{"$ref":"#/components/schemas/CrossChartAspectPattern"}},"fixedStarConjunctions":{"type":"array","items":{"type":"object","additionalProperties":true}},"midpointActivations":{"type":"array","items":{"type":"object","additionalProperties":true}},"declinations":{"type":"array","items":{"type":"object","additionalProperties":true}},"declinationAspects":{"type":"array","items":{"type":"object","additionalProperties":true}},"transitToNatalDeclinationAspects":{"type":"array","items":{"$ref":"#/components/schemas/TransitDeclinationAspect"}}},"required":["timeResolutions","calcVersion","transitMoment","natalLocation","natalPlanets","natalHouses","houseSystem","ascendant","midheaven","transitPlanets","transitToNatalAspects","transitAspects","natalAspects"]},"SkyChart":{"type":"object","description":"Flat single-wheel sky projection.","properties":{"timeResolutions":{"type":"array","items":{"$ref":"#/components/schemas/ChartTimeResolution"}},"calcVersion":{"type":"string","description":"Deterministic fingerprint of chart-engine revision, TZDB release, and effective aspect orbs."},"moment":{"type":"string","format":"date-time","description":"UTC instant of the sky."},"planets":{"type":"array","items":{"$ref":"#/components/schemas/PlanetPosition"}},"aspects":{"type":"array","items":{"$ref":"#/components/schemas/Aspect"}},"houses":{"type":["array","null"],"items":{"$ref":"#/components/schemas/HouseCusp"},"description":"Present only if latitude/longitude supplied."},"ascendant":{"oneOf":[{"$ref":"#/components/schemas/EclipticPosition"},{"type":"null"}]},"midheaven":{"oneOf":[{"$ref":"#/components/schemas/EclipticPosition"},{"type":"null"}]},"houseSystem":{"oneOf":[{"$ref":"#/components/schemas/HouseSystem"},{"type":"null"}],"description":"House system used for the cusps. Null when latitude/longitude are omitted."}},"required":["timeResolutions","calcVersion","moment","planets","aspects"]},"TransitEventType":{"type":"string","enum":["AspectPerfection","SignIngress","Station","Lunation","Eclipse"],"description":"Type of astronomical event: AspectPerfection (two planets at an exact aspect angle), SignIngress (planet entering a new zodiac sign), Station (planet changing from retrograde to direct or vice versa), Lunation (new moon at 0° or full moon at 180° Sun-Moon angle), Eclipse (solar or lunar).\n"},"TransitEvent":{"type":"object","description":"A single astronomical event with UTC moment (refined to 1-minute accuracy), primary and optional secondary bodies, zodiac sign, ecliptic longitude, and event-specific detail.\n","properties":{"kind":{"$ref":"#/components/schemas/TransitEventType"},"moment":{"type":"string","format":"date-time","description":"UTC instant the event occurs (exact time refined via bisection)."},"primaryBody":{"$ref":"#/components/schemas/Planet","description":"For ingresses/stations/lunations: the moving body. For aspects: the faster planet (1st of the pair). For eclipses: Sun (solar) or Moon (lunar)."},"secondaryBody":{"oneOf":[{"$ref":"#/components/schemas/Planet"},{"type":"null"}],"description":"For aspects: the slower planet (2nd of the pair). For eclipses: the nearest lunar node (NorthNode or SouthNode). Null for ingresses, stations, lunations."},"sign":{"$ref":"#/components/schemas/ZodiacSign","description":"For ingresses: the sign entered. For other events: the sign of the primary body at the moment."},"longitude":{"type":"number","minimum":0,"maximum":360,"description":"Ecliptic longitude of the primary body at the moment (degrees)."},"detail":{"oneOf":[{"type":"string"},{"type":"null"}],"description":"Event-specific detail. For aspects: aspect type name (conjunction, opposition, square, trine, sextile; when includeMinorAspects is true also semi_sextile, semi_square, quintile, sesquiquadrate, bi_quintile, quincunx). Quincunx is classified as a minor aspect on this endpoint. For lunations: new_moon or full_moon. For stations: retrograde or direct. For eclipses: solar or lunar. Null for ingresses.\n"}},"required":["kind","moment","primaryBody","sign","longitude"]},"CalendarEventsRequest":{"type":"object","description":"Request for astronomical events over a date range. Dates are interpreted in the specified timezone; internally converted to UTC for computation. Range is capped at 90 days.\n","required":["from","to","timezoneId"],"properties":{"from":{"type":"string","format":"date","description":"Range start (inclusive), as a calendar date (e.g. 2026-01-01).","example":"2026-01-01"},"to":{"type":"string","format":"date","description":"Range end (inclusive). Must be >= from; span must not exceed 90 days.","example":"2026-02-28"},"timezoneId":{"type":"string","description":"IANA Tzdb timezone id (e.g. Europe/Amsterdam). Used to interpret from/to dates as local midnight boundaries.","example":"Europe/Amsterdam"},"includeMinorAspects":{"type":"boolean","default":false,"description":"When true, also return the six minor aspects (semi_sextile, semi_square, quintile, sesquiquadrate, bi_quintile, quincunx). Default false returns only the five major aspects.\n"}}},"CalendarEventsResponse":{"type":"object","description":"Calendar events response, containing a sorted array of astronomical events.","properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/TransitEvent"},"description":"Events sorted by moment (UTC). Empty array if no events in range."}},"required":["events"]}}}}