{
  "openapi": "3.0.1",
  "info": {
    "title": "Saju Four Pillars Calculator — Korean BaZi Birth Chart",
    "description": "Batch-computes Korean saju (사주) / BaZi four-pillar charts from birth timestamps, civil years 1900-2100 — a manseryeok engine, not a scraper. Each row carries the hour pillar under all seven conventions, plus 지장간, 십신 and 대운. Times that never existed or happened twice are flagged, not charted.",
    "version": "0.1",
    "x-build-id": "0iAO0d7HAW9EAt9tg"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/kdatafactory~saju-engine/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-kdatafactory-saju-engine",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/acts/kdatafactory~saju-engine/runs": {
      "post": {
        "operationId": "runs-sync-kdatafactory-saju-engine",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor and returns information about the initiated run in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/runsResponseSchema"
                }
              }
            }
          }
        }
      }
    },
    "/acts/kdatafactory~saju-engine/run-sync": {
      "post": {
        "operationId": "run-sync-kdatafactory-saju-engine",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "inputSchema": {
        "type": "object",
        "required": [
          "births"
        ],
        "properties": {
          "births": {
            "title": "Birth records (batch)",
            "type": "array",
            "description": "The batch of births to chart, up to 5,000 records per run. SUPPORTED BIRTH YEARS ARE 1900-2100 BY CIVIL YEAR — the year in 'date', not the 사주 solar year — and a record outside that range comes back as an 'out_of_range' row with null pillars instead of a guess. The difference shows at both ends: a 1900-01-10 birth IS charted and reports solar_year 1899 (입춘 1900 is on 1900-02-04), while the 丑月 of solar year 2100, which opens with 소한 on 2101-01-05 and runs to 입춘 on 2101-02-04, is NOT chartable, because those dates are civil 2101. The last chartable date is 2100-12-31, still inside 子月. One record in = exactly one dataset row out, in the same order, with your own 'id' echoed back so you can join results to your source table. Per record: 'date' (required, YYYY-MM-DD, Gregorian/양력 — convert lunar 음력 dates first; a record marked calendar:'lunar' is rejected, never guessed at), 'time' (HH:MM or HH:MM:SS, 24-hour; omit it if unknown and the hour pillar is returned as null rather than guessed), 'sex' ('male' or 'female' — needed only for 대운, whose direction follows 양남음녀; omit it and 'daeun' is null with a note), 'id' (any string key of yours), 'timezone' (IANA zone id, defaults below), 'longitude' (degrees east, used only for the solar-time conventions, defaults below — but REQUIRED on any record whose 'timezone' differs from the run's default zone, since the default longitude then belongs to a different place; such a record comes back as 'longitude_required' instead of being charted on the wrong meridian). BILLING: charted rows and flagged rows (a local time that never existed or happened twice) are billed; rows rejected as 'invalid_input', 'out_of_range' or 'longitude_required' are still returned, so your join keeps one row per record, but they are not billed. The three pre-filled records are the cases worth seeing: an ordinary 1990 birth, a 23:40 birth in Korea's 1955 UTC+09:30 summer time, and a 1961-08-10 00:15 birth — a wall-clock time that never existed.",
            "default": [
              {
                "id": "A-1990",
                "date": "1990-06-15",
                "time": "13:10",
                "sex": "male"
              },
              {
                "id": "B-1955",
                "date": "1955-07-10",
                "time": "23:40",
                "sex": "male"
              },
              {
                "id": "C-1961",
                "date": "1961-08-10",
                "time": "00:15",
                "sex": "female"
              }
            ]
          },
          "hourPillarConvention": {
            "title": "Default hour-pillar convention",
            "enum": [
              "clock_midnight",
              "clock_23h",
              "true_solar_midnight",
              "true_solar_23h",
              "lmt_midnight",
              "lmt_23h",
              "mixed_clock_day_true_solar_hour"
            ],
            "type": "string",
            "description": "Which convention fills the top-level 'hour_pillar', 'day_pillar', 'element_counts', 'ten_gods' and 'hidden_stems' of each row. Every row always contains ALL seven conventions in 'hour_pillar_by_convention', each labelled with what it did — this setting only nominates your default, and the default is a default, not a claim that it is the correct one. The two choices being combined are the time basis (the clock time as recorded, mean local solar time from the longitude alone, or true solar time which adds the equation of time) and the day boundary (00:00 or 23:00; this is the 야자시/조자시 discussion). Schools disagree, so this Actor reports every convention and ranks none of them.",
            "default": "clock_midnight"
          },
          "tenGodsBranchBasis": {
            "title": "십신 basis for the four branches",
            "enum": [
              "jeonggi",
              "positional"
            ],
            "type": "string",
            "description": "A 지지 has no stem of its own, so reading its 십신 needs a choice, and the two defensible answers differ for exactly 子·午·巳·亥 — the four 體用 inversions. 'jeonggi' reads each branch through its 정기 지장간 (the 용 reading, what mainstream 만세력 display); 'positional' reads it by the branch's own 오행 with its positional polarity (the 체 reading). Every row returns BOTH: your choice in 'ten_gods' and the other in 'ten_gods_branch_alternate'. This setting only decides which is which.",
            "default": "jeonggi"
          },
          "daeunCount": {
            "title": "How many 대운 pillars",
            "minimum": 1,
            "maximum": 12,
            "type": "integer",
            "description": "How many ten-year 대운 luck pillars to list per chart. 대운 needs the record's 'sex' (its direction follows 양남음녀) and is null without it. The distance to the governing 절기 is measured as pure instant arithmetic, so 대운수 does not depend on the hour-pillar convention you picked. The 1st 대운 is the month pillar plus or minus one — the month pillar itself is not emitted as a 0th 대운, which some engines call 초운/태운.",
            "default": 10
          },
          "defaultTimezone": {
            "title": "Default timezone (IANA id)",
            "type": "string",
            "description": "IANA time-zone id used for any record that omits 'timezone'. Historical offsets are read from the tz database that ships with the runtime — including Korea's UTC+08:30 eras (1908-04-01 to 1911-12-31 and 1954-03-20 to 1961-08-10), the local mean time of +08:27:52 before 1908-04-01, and the +09:30 summer time of 1955-1960 — never from a fixed meridian rule. Each row reports the offset it used and the tz database version.",
            "default": "Asia/Seoul"
          },
          "defaultLongitude": {
            "title": "Default longitude (°E) for the solar-time conventions",
            "minimum": -180,
            "maximum": 180,
            "type": "number",
            "description": "Longitude in decimal degrees east, used for the mean-local-time and true-solar-time conventions when a record omits 'longitude'. 126.978 is Seoul. DEGREES ARE CONVERTED TO HOURS BY DIVIDING BY 15 (15° = 1 hour): mean local time = UTC + longitude/15 hours, i.e. the clock time shifted by (longitude - the meridian implied by the zone's actual offset)/15 hours; true solar time adds the equation of time. For Seoul's 126.978°E on a +09:00 clock that shift is about -32 minutes, and on the +08:30 clock of 1954-1961 it is about -2 minutes, not -32. Latitude is irrelevant to solar time, so none is asked for. Both components are reported per row.",
            "default": 126.978
          },
          "nonexistentTimePolicy": {
            "title": "If the local time never existed",
            "enum": [
              "flag",
              "shift_forward"
            ],
            "type": "string",
            "description": "Every forward clock jump erases a window of wall-clock time, and most of Korea's fall inside the 23:00-01:00 자시 hour (e.g. 1961-08-10 00:00-00:29 and 1912-01-01 00:00-00:29). 'flag' returns the row with null pillars, a note naming the clock change, and a warning — because the two possible readings of such a time usually fall on different days, and so give different day pillars. 'shift_forward' instead charts the first local time that did exist after the gap and records that in 'resolution_policy' and 'warnings'. Either way the row is pushed and billed — a row that names the clock change is the analysis, not a failure.",
            "default": "flag"
          },
          "ambiguousTimePolicy": {
            "title": "If the local time happened twice",
            "enum": [
              "flag",
              "earlier",
              "later"
            ],
            "type": "string",
            "description": "Every backward clock jump repeats a window of wall-clock time (e.g. 1954-03-20 23:30-23:59 in Seoul, again inside the 자시 hour). 'flag' returns the row with null pillars, a note, and BOTH instants in 'utc_instant' and 'alternate_utc_instant'; 'earlier' or 'later' picks the first or second occurrence and records the choice in 'resolution_policy' and 'warnings'. Either way the row is pushed and billed — a row that names the clock change is the analysis, not a failure.",
            "default": "flag"
          },
          "boundaryFlagMinutes": {
            "title": "Solar-term boundary flag window (minutes)",
            "minimum": 0,
            "maximum": 1440,
            "type": "integer",
            "description": "When a birth falls within this many minutes of a 절기 (節) instant, the row sets 'near_term_boundary' and adds a warning, because the month pillar turns on that instant. This threshold is a PRODUCT CHOICE and NOT a measured ephemeris error bound. What HAS been measured, term by term on 2026-09-29: the instants agree with the National Astronomical Observatory of Japan's 暦要項 (2025-2026) and the Hong Kong Observatory's tables (2026-2028) to within 59 seconds, and with NAOJ's 長期版 for 1912, 1961, 1990 and 2050 to within 48 seconds — but at 2100 they run 110-142 seconds EARLY, because the limit there is ΔT (the Earth's future rotation), which is predicted rather than computed and which NAOJ and this ephemeris predict differently. 한국천문연구원 (KASI)'s own published 절기 tables have still not been compared. Every row also carries the signed 'minutes_to_nearest_term_boundary' so you can apply your own threshold.",
            "default": 10
          }
        }
      },
      "runsResponseSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "actId": {
                "type": "string"
              },
              "userId": {
                "type": "string"
              },
              "startedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "finishedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "status": {
                "type": "string",
                "example": "READY"
              },
              "meta": {
                "type": "object",
                "properties": {
                  "origin": {
                    "type": "string",
                    "example": "API"
                  },
                  "userAgent": {
                    "type": "string"
                  }
                }
              },
              "stats": {
                "type": "object",
                "properties": {
                  "inputBodyLen": {
                    "type": "integer",
                    "example": 2000
                  },
                  "rebootCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "restartCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "resurrectCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "computeUnits": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "options": {
                "type": "object",
                "properties": {
                  "build": {
                    "type": "string",
                    "example": "latest"
                  },
                  "timeoutSecs": {
                    "type": "integer",
                    "example": 300
                  },
                  "memoryMbytes": {
                    "type": "integer",
                    "example": 1024
                  },
                  "diskMbytes": {
                    "type": "integer",
                    "example": 2048
                  }
                }
              },
              "buildId": {
                "type": "string"
              },
              "defaultKeyValueStoreId": {
                "type": "string"
              },
              "defaultDatasetId": {
                "type": "string"
              },
              "defaultRequestQueueId": {
                "type": "string"
              },
              "buildNumber": {
                "type": "string",
                "example": "1.0.0"
              },
              "containerUrl": {
                "type": "string"
              },
              "usage": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "integer",
                    "example": 1
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "usageTotalUsd": {
                "type": "number",
                "example": 0.00005
              },
              "usageUsd": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "number",
                    "example": 0.00005
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}