Saju Compatibility API — a 0–100 match score from two birthdates.

Add Korean Saju (사주 / Four Pillars of Destiny, the Korean cousin of Chinese Bazi) compatibility scoring to a dating, matchmaking, or social app with one POST request. The /compatibility endpoint returns a single 0–100 score plus a transparent breakdown you can render in a UI — no astrology library to build yourself.

What you send and get back

Post two people (person_a and person_b), each with a solar birthdate. Use hour: -1 when the birth time is unknown. The response is a flat JSON object: a top-level score, a breakdown, and a small summary of each person.

FieldMeaning
scoreOverall 0–100 compatibility score.
breakdown.element_balanceHow evenly the two charts cover the Five Elements (wood, fire, earth, metal, water).
breakdown.day_master_relationRelationship between the two Day Masters (same, generating, or controlling element).
breakdown.branch_harmonyBonus when the Earthly Branches form a harmony (육합 / 삼합).
breakdown.branch_clashPenalty when the Earthly Branches clash (충).
person_a, person_bEach person's day_master, day_master_element, and zodiac animal.

Call it

Send your free-tier key in the X-API-Key header. Get a key in the quickstart if you do not have one yet.

curl -X POST https://saju-api.pages.dev/api/v1/compatibility \
  -H "X-API-Key: sajuapi_free_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "person_a": { "year": 1990, "month": 5,  "day": 15, "hour": 14, "gender": "M" },
    "person_b": { "year": 1992, "month": 11, "day": 3,  "hour": 9,  "gender": "F" },
    "lang": "en"
  }'
const res = await fetch("https://saju-api.pages.dev/api/v1/compatibility", {
  method: "POST",
  headers: {
    "X-API-Key": "sajuapi_free_YOUR_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    person_a: { year: 1990, month: 5,  day: 15, hour: 14, gender: "M" },
    person_b: { year: 1992, month: 11, day: 3,  hour: 9,  gender: "F" },
    lang: "en",
  }),
});
const data = await res.json();
console.log(data.score);              // 0-100
console.log(data.breakdown);          // { element_balance, day_master_relation, ... }
import requests

res = requests.post(
    "https://saju-api.pages.dev/api/v1/compatibility",
    headers={"X-API-Key": "sajuapi_free_YOUR_KEY"},
    json={
        "person_a": {"year": 1990, "month": 5,  "day": 15, "hour": 14, "gender": "M"},
        "person_b": {"year": 1992, "month": 11, "day": 3,  "hour": 9,  "gender": "F"},
        "lang": "en",
    },
)
data = res.json()
print(data["score"])       # 0-100
print(data["breakdown"])   # element_balance, day_master_relation, branch_harmony, branch_clash

Example response

{
  "score": 78,
  "breakdown": {
    "element_balance":     22,
    "day_master_relation": 30,
    "branch_harmony":      25,
    "branch_clash":         0
  },
  "person_a": { "day_master": "...", "day_master_element": "metal", "zodiac": "horse" },
  "person_b": { "day_master": "...", "day_master_element": "water", "zodiac": "monkey" },
  "tier":      "free",
  "remaining": 98
}
The four breakdown parts are summed and clamped into the 0–100 range, so the score is explainable: you can show users why a pairing scored the way it did instead of an opaque number. A clash (branch_clash) lowers the score; a harmony raises it.

Designing the match screen

A few patterns that work well when you surface this in product:

Errors

StatusMeaning
400invalid_input with a reason such as person_a_year_out_of_range or person_b_gender_must_be_M_or_F. Year range is 1920–2050.
401Missing or malformed X-API-Key.
405Use POST for this endpoint.
429Daily quota for your tier exceeded.

Next steps