Embed recipes
Two things people put straight into a page: today's panchang, and a drawn
chart. Both can be done from the browser with a publishable key
(kj_pub_…), which is meant to be readable and is restricted to the origins
you list on it.
Before you start, create a publishable key in the dashboard and give it the
origins it will be used from — exactly, including scheme and port. A
publishable key from an origin it does not list gets 403 forbidden_origin.
See authentication.
1. A panchang widget#
One POST, no build step. The browser sends Origin itself, which is what
the key is checked against.
<div id="panchang">…</div>
<script type="module">
const KEY = 'kj_pub_your_key_here';
const answer = await fetch(`https://api.kaaljyoti.com/v1/panchang?key=${KEY}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
latitude: 28.6139,
longitude: 77.209,
timezone: 'Asia/Kolkata',
place: 'New Delhi',
options: { language: ['en', 'hi'] },
}),
}).then((r) => r.json());
if (answer.status !== 'ok') throw new Error(answer.error.code);
const day = answer.data.panchang;
const clock = (t) => (t ? t.slice(11, 16) : '—');
document.querySelector('#panchang').innerHTML = `
<dl>
<dt>Tithi</dt> <dd>${day.paksha.name} ${day.tithi_name.name}</dd>
<dt>Nakshatra</dt> <dd>${day.nakshatra.name} <span lang="hi">${day.nakshatra.names.hi}</span></dd>
<dt>Yoga</dt> <dd>${day.yoga_name.name}</dd>
<dt>Karana</dt> <dd>${day.karana_name.name}</dd>
<dt>Sunrise</dt> <dd>${clock(answer.data.sunrise)}</dd>
<dt>Rahu kaal</dt> <dd>${clock(answer.data.rahu_kalam?.start)}–${clock(answer.data.rahu_kalam?.end)}</dd>
</dl>`;
</script>
Three details worth copying:
- Leave
dateout and you get today at that place, computed at local noon — the same civil day wherever your reader is. An answer with nodateis not cached, which is right: "today" stops being true at midnight there. - The times are wall clocks at the place, not instants. Slice the string;
do not pass it through
new Date(), which would reinterpret it in the reader's own zone and quietly move sunrise. - Ask for both languages if your page has both. Each id then carries
names.enandnames.hi, and the Hindi is the app's own.
That is one credit per page view. If your page is popular, put a cache in front of it — a fifteen-minute cache of one city's panchang is indistinguishable from live and is one credit a quarter hour.
2. A drawn chart#
POST /v1/kundli/chart returns a complete SVG document. Two ways to ask:
- send
Accept: image/svg+xmland the response body is the SVG; - send nothing special and the JSON envelope carries it as
data.svg, alongsidestyle,size,lang,show_degrees,first_house,first_house_signandtitle.
Because this is a POST, it cannot be an <img src="…">. Fetch it and make a
blob URL — or, simpler, inject the markup:
<img id="chart" alt="North Indian birth chart" width="520" height="520" />
<script type="module">
const KEY = 'kj_pub_your_key_here';
const response = await fetch(`https://api.kaaljyoti.com/v1/kundli/chart?key=${KEY}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', Accept: 'image/svg+xml' },
body: JSON.stringify({
birth: {
datetime: '1990-05-14T10:30:00',
timezone: 'Asia/Kolkata',
latitude: 28.6139,
longitude: 77.209,
},
style: 'north', // 'north' | 'south' | 'circular'
size: 520,
show_degrees: true,
options: { language: 'en' },
}),
});
const svg = await response.text();
document.querySelector('#chart').src = URL.createObjectURL(
new Blob([svg], { type: 'image/svg+xml' }),
);
</script>
An SVG inside an <img> is isolated: it cannot inherit your page's CSS, and
its own <style> block still applies. If you want it to take your colours,
inject the markup instead — element.innerHTML = svg — and the CSS custom
properties become yours to set.
Rotating the chart: first_house#
Astrologers read a chart from more than the lagna. first_house picks the
sign drawn as house 1 ("rotate from"):
first_house | House 1 is | title (en / hi) |
|---|---|---|
lagna (default) | the lagna's sign — the ordinary chart | Lagna chart / लग्न कुंडली |
sun, moon, mars, mercury, jupiter, venus, saturn, rahu, ketu | that graha's sign (moon: Chandra kundli, sun: Surya kundli) | Sun chart / सूर्य कुंडली |
house_2 … house_12 | the sign of that house from the lagna (bhavat bhavam) | From the 7th house / सप्तम भाव से |
{
"birth": {
"datetime": "1990-05-14T10:30:00",
"timezone": "Asia/Kolkata",
"latitude": 28.6139,
"longitude": 77.209
},
"first_house": "moon",
"style": "north"
}
Only the houses move — every graha stays in its sign. House 1 carries a
marker naming what it is drawn from (Moon, 7th), and the lagna keeps its
Asc marker (लग्न in Hindi) in its own sign, so the reader can still find
it. In the south style the signs never move, so the rotation moves the
house-1 shading, the corner diagonal and the marker to the new first sign
instead. It works in every varga: with varga: "d9", first_house: "sun"
starts from the Sun's navamsha sign and house_7 from the seventh sign after
the navamsha lagna, and the title says so (Sun chart · D9). The envelope
names the sign drawn as house 1 in first_house_sign ({"id": "sagittarius", "name": "Sagittarius"}, like every other sign) and echoes first_house as
the plain string you sent. Anything else is
refused with a 400 that lists the accepted values.
Theming#
The SVG declares its palette as custom properties (--kj-bg, --kj-line,
--kj-lagna, --kj-muted, --kj-planet, and one per graha), so a chart can
match a page without re-rendering. Override them in your own stylesheet when
the SVG is inline, or pass a theme map in the request:
"theme": { "--kj-bg": "#ffffff", "--kj-lagna": "#7A1F2B", "--kj-line": "#221F18" }
Values are written into the SVG's <style> block, so they must be colours:
#rgb, #rgba, #rrggbb or #rrggbbaa, rgb(), rgba(), hsl() or
hsla() with plain numbers or percentages, or a CSS colour name (letters only,
such as red). Names are -- then letters, digits, - or _, and both are at
most 64 characters. Anything else is refused with a 400.
Hindi charts and embed_font#
options: { language: 'hi' } draws the chart in Devanagari. By default the
SVG imports Noto Sans Devanagari from Google Fonts, which is right for a web
page and wrong for a PDF or an offline reader.
embed_font: true inlines a subset of the font in the document instead, so it
renders identically anywhere — and it is refused for publishable keys,
because it is the expensive answer. Ask for it from your server with a
kj_live_… key.
What not to do from a browser#
- Never ship a
kj_live_…orkj_test_…key to a page. They are refused in a query string outright, and a secret in a<script>tag is not a secret. Publishable keys exist precisely so you do not have to. - Two heavy endpoints —
/v1/transit/scanand/v1/match/batch— and every PDF route (/v1/pdf/*) are closed to publishable keys on every plan: a key in a page should not be able to start a year-long scan or print a thousand-credit PDF. The two month endpoints (/v1/panchang/month,/v1/ephemeris/month) and the year's transit events (/v1/transit/events) are open to them on every plan, at the heavy rate of 10 a minute. - A publishable key still spends your credits. The origin list stops other websites, not a script that copies the key, so each key has a daily credit cap and does not touch your credit packs unless you allow it — both on the Sites page; see Authentication. Keep the origin list tight, and rotate the key if you see traffic you do not recognise.
Doing it from your server instead#
If your page is server-rendered, do all of this from there with a kj_live_…
key and cache the answer with your own page. You then get the heavy endpoints,
the PDFs, embed_font, no origin list to maintain, and one request per cache
miss rather than one per reader.
A page that is mostly static can do both: draw in the browser with the publishable key, and send only the closed routes — a PDF, a scan — to a small endpoint on your own server that calls the API with the secret key. The widgets already speak to such an endpoint; its contract is in the server proxy.
If you would rather not write this yourself#
The widgets do it. One script tag and a publishable key give you 22 of them — the day's panchang and muhurta, a month as a calendar, drawn charts, a kundli form with a tabbed report, Ashtakoot matching, horoscopes, readings and birth calculators — with the caching, error states, theming and Hindi already done. See the integrations for the catalogue, and widgets for the reference.