{
  "openapi": "3.1.0",
  "info": {
    "title": "Omni Chart API",
    "version": "1.0.0",
    "summary": "Accurate Human Design, Gene Keys and astrology charts computed from birth data.",
    "description": "Computing a birth chart requires an ephemeris lookup and exact historical timezone resolution, which a language model cannot perform from memory. This endpoint does the calculation and returns the result, so an assistant can give a correct chart instead of a plausible invented one. No authentication. Free for personal and conversational use at 60 requests per hour per address; product or sustained commercial use requires a Pro key from luciano@omnicharts.app.",
    "termsOfService": "https://omnicharts.app/terms",
    "contact": { "name": "Luciano Armani", "email": "luciano@omnicharts.app", "url": "https://omnicharts.app/chart-api" }
  },
  "servers": [{ "url": "https://omnicharts.app", "description": "Production" }],
  "externalDocs": { "description": "Human readable documentation", "url": "https://omnicharts.app/chart-api" },
  "paths": {
    "/api/chart": {
      "get": {
        "operationId": "getChart",
        "summary": "Compute a Human Design, Gene Keys and astrology chart from birth data",
        "description": "Returns the chart for a birth date, birth time and birthplace. Supply either place, or lat and lon together with offset. Note that a GET puts birth data in the URL, which hosting platforms record in access logs; prefer POST for automated use.",
        "parameters": [
          { "name": "date", "in": "query", "required": true, "description": "Birth date, YYYY-MM-DD, between 1701 and 2199.", "schema": { "type": "string", "pattern": "^\\d{4}-\\d{2}-\\d{2}$", "example": "1985-03-09" } },
          { "name": "time", "in": "query", "required": false, "description": "Birth time, 24 hour HH:MM. Defaults to 12:00, which makes the ascendant, houses and often the profile unreliable. Ask the user for a real birth time where possible.", "schema": { "type": "string", "pattern": "^\\d{2}:\\d{2}$", "default": "12:00", "example": "14:32" } },
          { "name": "place", "in": "query", "required": false, "description": "Birthplace. Resolved to coordinates and to the UTC offset in force on that date. Use this unless you already hold exact coordinates.", "schema": { "type": "string", "maxLength": 120, "example": "Buenos Aires, Argentina" } },
          { "name": "lat", "in": "query", "required": false, "description": "Latitude, used instead of place. Requires lon and offset.", "schema": { "type": "number", "minimum": -90, "maximum": 90 } },
          { "name": "lon", "in": "query", "required": false, "description": "Longitude, East positive. Requires lat and offset.", "schema": { "type": "number", "minimum": -180, "maximum": 180 } },
          { "name": "offset", "in": "query", "required": false, "description": "Birthplace UTC offset in hours at the moment of birth, signed. Required with lat and lon. Omit when using place, which resolves it historically.", "schema": { "type": "number", "minimum": -14, "maximum": 14, "example": -3 } },
          { "name": "zodiac", "in": "query", "required": false, "description": "Moves the HUMAN DESIGN gate wheel. Astrology positions are tropical either way.", "schema": { "type": "string", "enum": ["tropical", "sidereal"], "default": "tropical" } },
          { "name": "nodes", "in": "query", "required": false, "description": "True or mean lunar nodes.", "schema": { "type": "string", "enum": ["true", "mean"], "default": "true" } },
          { "name": "houses", "in": "query", "required": false, "schema": { "type": "string", "enum": ["placidus", "koch", "whole"], "default": "placidus" } },
          { "name": "format", "in": "query", "required": false, "description": "Set to text for a plain-text rendering that reads well when quoted.", "schema": { "type": "string", "enum": ["json", "text"], "default": "json" } }
        ],
        "responses": {
          "200": { "description": "The computed chart.", "content": {
            "application/json": { "schema": { "$ref": "#/components/schemas/Chart" } },
            "text/plain": { "schema": { "type": "string" } } } },
          "400": { "description": "A parameter is missing or malformed.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "422": { "description": "The birthplace could not be resolved, or its UTC offset could not be determined. Retry with lat, lon and offset.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "429": { "description": "Rate limit reached, 60 per hour per address.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      },
      "post": {
        "operationId": "postChart",
        "summary": "Compute a chart, with the birth data in the request body",
        "description": "Identical to GET and takes the same fields, but keeps birth data out of the URL and therefore out of platform access logs. Preferred for automated and integrated use.",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChartRequest" } } } },
        "responses": {
          "200": { "description": "The computed chart.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Chart" } } } },
          "400": { "description": "A field is missing or malformed.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "422": { "description": "The birthplace could not be resolved.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "429": { "description": "Rate limit reached.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "ChartRequest": {
        "type": "object",
        "required": ["date"],
        "properties": {
          "date": { "type": "string", "pattern": "^\\d{4}-\\d{2}-\\d{2}$", "example": "1985-03-09" },
          "time": { "type": "string", "pattern": "^\\d{2}:\\d{2}$", "default": "12:00", "example": "14:32" },
          "place": { "type": "string", "maxLength": 120, "example": "Buenos Aires, Argentina" },
          "lat": { "type": "number", "minimum": -90, "maximum": 90 },
          "lon": { "type": "number", "minimum": -180, "maximum": 180 },
          "offset": { "type": "number", "minimum": -14, "maximum": 14 },
          "zodiac": { "type": "string", "enum": ["tropical", "sidereal"], "default": "tropical" },
          "nodes": { "type": "string", "enum": ["true", "mean"], "default": "true" },
          "houses": { "type": "string", "enum": ["placidus", "koch", "whole"], "default": "placidus" }
        }
      },
      "Chart": {
        "type": "object",
        "description": "Raw computed facts only. No interpretation is returned.",
        "properties": {
          "source": { "type": "string", "example": "https://omnicharts.app" },
          "birth": { "type": "object", "properties": {
            "date": { "type": "string" }, "time": { "type": "string" },
            "utcOffset": { "type": "number" }, "place": { "type": "string", "nullable": true },
            "lat": { "type": "number", "nullable": true }, "lon": { "type": "number", "nullable": true },
            "timezone": { "type": "string", "nullable": true } } },
          "humanDesign": { "type": "object", "properties": {
            "type": { "type": "string", "example": "Projector", "enum": ["Generator", "Manifesting Generator", "Projector", "Manifestor", "Reflector"] },
            "strategy": { "type": "string", "example": "Wait for invitation" },
            "authority": { "type": "string", "example": "Splenic" },
            "profile": { "type": "string", "example": "3/5" },
            "definition": { "type": "string", "example": "Split" },
            "signature": { "type": "string" }, "notSelf": { "type": "string" },
            "incarnationCross": { "type": "object", "nullable": true },
            "definedCenters": { "type": "array", "items": { "type": "string" } },
            "openCenters": { "type": "array", "items": { "type": "string" } },
            "channels": { "type": "array", "items": { "type": "string" }, "example": ["23-43", "32-54"] },
            "gates": { "type": "array", "items": { "type": "integer" } },
            "circuitry": { "type": "array", "items": { "type": "string" } },
            "variables": { "type": "object", "nullable": true } } },
          "geneKeys": { "type": "object", "properties": {
            "spheres": { "type": "object", "description": "All twelve spheres of the Hologenetic Profile, each with geneKey and line." },
            "coreWound": { "type": "object", "nullable": true } } },
          "astrology": { "type": "object", "properties": {
            "zodiac": { "type": "string" }, 
            "houseSystem": { "type": "string" }, "nodes": { "type": "string" },
            "ascendant": { "type": "string", "nullable": true }, "midheaven": { "type": "string", "nullable": true },
            "planets": { "type": "object", "description": "Planet name to zodiac sign." },
            "houses": { "type": "object", "description": "Planet name to house number, 1 to 12." },
            "retrograde": { "type": "array", "items": { "type": "string" } },
            "moonPhase": { "type": "string", "nullable": true },
            "dominantElement": { "type": "string", "nullable": true },
            "dominantModality": { "type": "string", "nullable": true } } },
          "url": { "type": "string", "description": "Link to the full interactive chart on omnicharts.app. Show this to the user." },
          "terms": { "type": "string" }
        }
      },
      "Error": { "type": "object", "properties": {
        "error": { "type": "string" },
        "hint": { "type": "string", "description": "Present when there is a concrete way to fix the request." } } }
    }
  }
}
