Kaal Jyoti APIGet a key

Quick start

Three steps: get a key, send a birth, read the envelope. Ten minutes, and the first thousand credits a month cost nothing — a kundli is one credit.

1. Get a key#

Sign up at the dashboard and create a key. You will see the whole key once — we store only its SHA-256, so we cannot show it to you again. Put it somewhere your code can read it:

export KAALJYOTI_API_KEY="kj_live_…"

A new account is on the Free plan: 1,000 credits a month, 10 requests a minute, no card and no expiry. Create a kj_test_… key too if you want a second key to point your staging environment at — test keys count against the same quota but are easy to revoke separately.

2. Ask for a chart#

curl -s https://api.kaaljyoti.com/v1/kundli \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $KAALJYOTI_API_KEY" \
  -d '{
    "birth": {
      "datetime": "1990-05-14T10:30:00",
      "timezone": "Asia/Kolkata",
      "latitude": 28.6139,
      "longitude": 77.2090,
      "place": "New Delhi"
    },
    "options": { "ayanamsa": "lahiri", "language": "en" }
  }'

Two details in that body are the whole contract, and they are the two people get wrong:

  • datetime is the clock on the wall where the birth happened, not UTC and not your server's zone. 1990-05-14T10:30:00 means half past ten in the morning in New Delhi, and timezone says which wall that was.
  • Give timezone or utc_offset, or neither — never both. With neither, the API works the zone out from the coordinates and tells you what it used. Giving both is a 400: they can disagree, and we will not guess which one you meant. See time zones.

Everything else has a default. options.ayanamsa is lahiri, options.language is en, and you can leave options out entirely.

3. Read the envelope#

Every success looks the same:

{ "status": "ok", "data": { … }, "meta": { … } }

data is the calculation. meta says how it was computed — which is what you show a user who asks why a number is what it is:

"meta": {
  "cached": false,
  "ayanamsa": { "id": "lahiri", "value": 23.7257290910… },
  "timezone": { "name": "Asia/Kolkata", "utc_offset": "+05:30", "source": "given" },
  "engine": "0.15.2",
  "compute_ms": 1,
  "language_fallback": [],
  "credits": 1
}

source: "given" means you named the zone; "derived" means we worked it out from the coordinates. engine is the calculation engine's version — pin it in your own logs and a future difference is explainable rather than mysterious. credits is what this request cost: 1 for a kundli.

Inside data, every id comes back with a name attached:

"lagna_sign": { "id": "cancer", "name": "Cancer" }

Ask for two languages — "language": ["en", "hi"] — and you get both:

"nakshatra": { "id": "vishakha", "name": "Vishakha", "names": { "en": "Vishakha", "hi": "विशाखा" } }

The id is the stable, machine-readable half and never changes. The name is for people. Every id is lower-case snake_case, the panchang's included — a tithi comes back as { "id": "dashami", "name": "Dashami" }, a month as { "id": "ashwina", "name": "Ashwina" }.

The whole answer, trimmed
{
  "status": "ok",
  "data": {
    "ascendant": 99.0467252886…,
    "ascendant_dms": "99°02'48.2\"",
    "lagna_sign": { "id": "cancer", "name": "Cancer" },
    "moon_sign": { "id": "sagittarius", "name": "Sagittarius" },
    "positions": {
      "sun": {
        "longitude": 29.4246346912…,
        "longitude_dms": "29°25'28.7\"",
        "sign": { "id": "aries", "name": "Aries" },
        "nakshatra": { "id": "krittika", "name": "Krittika" },
        "pada": 1,
        "speed": 0.9646146190…,
        "is_retrograde": false
      },
      "moon": { … }
    },
    "houses": [ … ], "house_cusps": [ … ], "panchang": { … }, "yogas": [ … ]
  },
  "meta": {
    "cached": false,
    "ayanamsa": { "id": "lahiri", "value": 23.7257290910… },
    "timezone": { "name": "Asia/Kolkata", "utc_offset": "+05:30", "source": "given" },
    "engine": "0.15.2",
    "compute_ms": 1,
    "language_fallback": [],
    "credits": 1
  }
}

A failure#

Failures have their own shape, and it always carries a code and a link:

{
  "status": "error",
  "error": {
    "code": "validation_error",
    "message": "give either timezone or utc_offset, not both",
    "field": "birth.utc_offset",
    "docs": "https://kaaljyoti.com/api/docs/errors#validation_error"
  }
}

Branch on error.code, never on the message — messages get clearer over time, codes do not. The full list is on the errors page, and a refused request costs nothing.

Something smaller to start with#

A panchang needs no birth at all — just a place:

curl -s https://api.kaaljyoti.com/v1/panchang \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $KAALJYOTI_API_KEY" \
  -d '{
    "latitude": 28.6139,
    "longitude": 77.2090,
    "timezone": "Asia/Kolkata",
    "place": "New Delhi",
    "options": { "language": ["en", "hi"] }
  }'

Where to go next#

Base URL for everything: https://api.kaaljyoti.com/v1.