divyastroapi
v0.1.1
Published
Official Node.js / TypeScript SDK for DivyAstroAPI — Vedic & Western astrology, panchang, matchmaking, dashas, numerology and tarot. DrikPanchang-level precision, pay-per-call.
Maintainers
Readme
divyastroapi
Official Node.js / TypeScript SDK for DivyAstroAPI — a B2B Vedic & Western astrology API with DrikPanchang-level precision and pay-per-call billing.
- ✅ 287 endpoints, fully typed, across 21 namespaces — panchang, charts, dashas, matchmaking, transits, horoscopes, numerology, tarot, muhurta, reports, narratives, and a complete Western (tropical) module.
- ✅ Zero runtime dependencies — uses the platform
fetch(Node 18+, Bun, Deno, and edge / serverless runtimes). Server-side by design — see Authentication. - ✅ ESM + CommonJS with bundled
.d.tstypes. - ✅ Typed errors, automatic retries (429/5xx) with
Retry-After, timeouts, and a generic escape hatch for any endpoint. - ✅ Branded PDF reports (optional) — turn report JSON into white-label, print-ready kundli / matchmaking / numerology / horoscope PDFs. See Branded PDF reports.
npm install divyastroapiGet an API key at https://divyastroapi.com/dashboard/keys.
Quick start
import { DivyAstro } from "divyastroapi";
const client = new DivyAstro({ apiKey: "dv_live_..." });
// or: new DivyAstro({ apiKey: process.env.DIVYASTRO_API_KEY })
// or just: new DivyAstro("dv_live_...")
// Today's panchang for a location
const tithi = await client.panchang.tithi({
lat: 28.6139,
lon: 77.209,
tz: "Asia/Kolkata",
});
// A Vedic birth chart
const planets = await client.chart.planets({
date: "1990-01-15",
time: "10:30",
tz: "Asia/Kolkata",
lat: 19.076,
lon: 72.8777,
});
// Kundli matchmaking score
const match = await client.milan.ashtakootaTotal({
boy: { date: "1988-05-04", time: "06:15", tz: "Asia/Kolkata", lat: 28.61, lon: 77.20 },
girl: { date: "1992-03-20", time: "21:40", tz: "Asia/Kolkata", lat: 19.07, lon: 72.87 },
});CommonJS works too:
const { DivyAstro } = require("divyastroapi");
Authentication
Your API key (dv_live_…) authenticates every request and is sent as a
Authorization: Bearer … header. Provide it in any of three ways:
new DivyAstro({ apiKey: "dv_live_..." }); // 1. explicit (recommended)
new DivyAstro("dv_live_..."); // 2. shorthand
new DivyAstro(); // 3. reads process.env.DIVYASTRO_API_KEYIf no key is found (neither argument nor env var), the constructor throws a clear error. Get a key at https://divyastroapi.com/dashboard/keys.
🔒 Keep your key secret — use the SDK server-side
A
dv_live_…key carries your account's full billing access. Use this SDK from a server, serverless function, or edge runtime — and load the key from an environment variable / secrets manager, never hard-coded. Do not embed the key in browser, mobile, desktop, or any client-side code, where end users could extract it and run up your bill. For client apps, call DivyAstroAPI from your own backend and forward the results.(Need PDFs in the browser? The dependency-free
divyastroapi/pdfrender*Htmlfunctions take no key and are safe to run anywhere — see Branded PDF reports.)
Configuration
const client = new DivyAstro({
apiKey: "dv_live_...", // or set DIVYASTRO_API_KEY
baseUrl: "https://api.divyastroapi.com", // override for local dev (http://localhost:8080)
timeoutMs: 30_000, // per-request timeout (default 30s)
maxRetries: 2, // retries on 429 / 5xx / network (default 2)
defaultHeaders: {}, // extra headers on every request
fetch: myFetch, // inject a custom fetch (older runtimes / proxies / tests)
});Input shapes
Most methods accept one of a few ergonomic input objects. The SDK maps these to the
exact wire parameters the API expects (birth.lat, boy.date, start_date, …) for you.
| Shape | Used by | Example fields |
|-------|---------|----------------|
| Moment | panchang.*, calendars | { lat, lon, tz, date?, time? } |
| Birth | chart.*, dasha.*, numerology, narratives, reports | { date, time, tz, lat, lon } |
| Boy/Girl | milan.*, reports.matchMaking | { boy: Birth, girl: Birth } |
| Two-person | western.synastry.*, western.composite.* | { personA: Birth, personB: Birth } |
| Rashi | horoscope.* | { rashi: "aries", date?, lang? } |
| Date range | eclipses.*, western.ingresses | { startDate, endDate } |
| Muhurta | muhurta.vivah, naamkaran, bestTime | { lat, lon, tz, startDate, endDate } |
Vedic endpoints also accept optional calculation settings: ayanamsa
("lahiri" default, "krishnamurti", "raman", …), houseSystem, and useTrueNode.
await client.chart.planets({ ...birth, ayanamsa: "krishnamurti", houseSystem: "placidus" });Namespaces
client.<namespace>.<method>(input) — every method returns the unwrapped data payload.
| Namespace | What it covers |
|-----------|----------------|
| panchang | tithi, nakshatra, yoga, karana, vara, sunrise/sunset, rahu-kaal, choghadiya, hora, muhurtas, monthly calendar, composite basic/advanced |
| chart | planets, ascendant, houses, divisional (D1–D60), dignity, aspects, shadbala, ashtakvarga, avakhada, KP, astro-details |
| dasha | full + current Vimshottari (5-level drill-down) and Yogini |
| milan | Ashtakoota (total / full / per-koota), mangal/nadi/shani dosha, navamsa & dasha compatibility |
| transit | positions, sade-sati, ashtakavarga, tarabala, vedha, double-transit, small-panoti |
| horoscope | daily / weekly / monthly by rashi |
| numerology | driver, conductor, soul, personality, destiny, full, advanced, challenges, periods |
| muhurta | vivah, naamkaran, griha-pravesh, vyapar, yatra, best-time, … |
| varshaphal | annual chart, lord, muntha, mudda-dasha, harsha-bala, tajika yogas |
| prashna | horary answer, chart, arudha, significators |
| eclipses | solar / lunar / all (date range, optional visibility) |
| calendar | Hindu month, ritu, samvatsara, adhik-maas |
| festivals | festivals by month / on a date |
| planetMoments | retrograde windows, ingress, combustion window, speed |
| ashtakavarga | sarva, bhinna (per planet), kaksha, transit-score |
| geo | place search, reverse geocode, timezone, place by id |
| tarot | cards, single card, daily, spread, yes/no |
| reports | kundli (lite/detailed/brihad), match-making, mangal-dosha, sade-sati, varshaphal, numerology, horoscopes |
| narrative | authored Vedic interpretations (lagna, planets, yogas, doshas, dasha-phal, outlooks, …) in en/hi/mr/bn/kn/ta/te/gu |
| remedies | remedies by rule id; mantra / pooja / vrat detail |
| western | full tropical module (see below) |
Western (tropical)
Nested under client.western.*:
await client.western.natal.chart({ date, time, tz, lat, lon, houseSystem: "placidus" });
await client.western.synastry.score({ personA, personB });
await client.western.transits.toNatal({ birth, date: "2026-06-16", time: "12:00", tz: "UTC" });
await client.western.returns.solar({ date, time, tz, lat, lon, returnYear: 2026 });
await client.western.profections.annual({ birthDate: "1990-01-15", ascSign: "capricorn" });Sub-namespaces: natal, houses, synastry, composite, davison, transits,
progressions, solarArc, returns, dignities, profections, zodiacalReleasing,
primaryDirections, interpretation, narrative, heliocentric, astrocartography,
eclipses, lunar, compatibility, plus firdaria, ingresses, retrogradeWindow.
Error handling
Every non-2xx response throws a typed error carrying the API's code, HTTP status,
and request_id:
import { DivyAstro, PaymentRequiredError, RateLimitError, DivyAstroError } from "divyastroapi";
try {
await client.chart.planets(birth);
} catch (err) {
if (err instanceof PaymentRequiredError) {
// 402 — out of credits / trial exhausted
} else if (err instanceof RateLimitError) {
console.log(`retry after ${err.retryAfter}s`);
} else if (err instanceof DivyAstroError) {
console.error(err.code, err.status, err.message, err.requestId);
}
}Error classes: BadRequestError (400), AuthenticationError (401),
PaymentRequiredError (402), PermissionError (403), NotFoundError (404),
RateLimitError (429), ServerError (5xx), DivyAstroConnectionError (network/timeout).
All extend DivyAstroError.
Typing the response
Responses are returned as the unwrapped data, typed unknown by default. Narrow it
with a type parameter, or pass { raw: true } to get the full { data, meta } envelope.
interface TithiData { number: number; name_en: string; paksha: string }
const t = await client.panchang.tithi<TithiData>({ lat, lon, tz });
const full = await client.request("/v1/panchang/tithi", { lat, lon, tz }, { raw: true });
// full = { data, meta: { request_id, cache, tier, ... } }Escape hatch
Call any /v1/* endpoint directly — useful for brand-new endpoints not yet wrapped:
const data = await client.request("/v1/panchang/tithi", { lat: 28.61, lon: 77.20, tz: "Asia/Kolkata" });
// client.get(...) is an aliasPer-call options
const controller = new AbortController();
await client.chart.planets(birth, { signal: controller.signal, timeoutMs: 5000 });Branded PDF reports
The divyastroapi/pdf subpath turns the JSON from client.reports.* into
branded, print-ready PDFs — same designs the API was built to produce
(cover page, planet/dasha tables, narrative sections), white-labelled with
your client's logo, colors, footer, and optional watermark.
Two layers:
render*Html(data, branding?)— pure, zero-dependency functions that produce a self-contained, branded HTML document. Run anywhere (Node, edge, browser).htmlToPdf(html, opts?)and the*Pdf(...)convenience wrappers — produce PDF bytes via the optionalpuppeteerpeer dependency.
npm install puppeteer # only if you want the SDK to emit PDF bytesimport { DivyAstro } from "divyastroapi";
import { kundliDetailedPdf, renderMatchMakingHtml } from "divyastroapi/pdf";
import { writeFileSync } from "node:fs";
const client = new DivyAstro({ apiKey: process.env.DIVYASTRO_API_KEY });
// 1. Fetch the report JSON
const report = await client.reports.kundliDetailed({
date: "1990-01-15", time: "10:30", tz: "Asia/Kolkata", lat: 19.076, lon: 72.8777,
lang: "hi",
});
// 2. Render a branded PDF in one call
const pdf = await kundliDetailedPdf(report, {
branding: {
companyName: "Acme Astro",
logoUrl: "https://cdn.acme.com/logo.png", // or a data: URI
primaryColor: "#6b21a8",
secondaryColor: "#9333ea",
footerText: "© Acme Astro — astrology for everyone",
watermarkText: "SAMPLE", // optional diagonal watermark
},
});
writeFileSync("kundli.pdf", pdf);Prefer to bring your own renderer (or run on serverless)? Use the HTML layer and convert however you like — it has no dependencies:
const html = renderMatchMakingHtml(matchReport, { primaryColor: "#b91c1c" });
// → feed `html` to your own Puppeteer/Playwright, a print service, Gotenberg, etc.Branding precedence: caller branding overrides the per-account branding
embedded in the report JSON, which falls back to neutral system defaults.
Security note: branding inputs are sanitized — colors are validated against a
safe-color allowlist, the watermark is CSS-escaped, and logoUrl is restricted to
http(s) / data:image/... / relative URLs (other schemes are dropped). Chromium
fetches logoUrl when rendering, so if you ever pass untrusted / end-user logo
URLs, run Puppeteer with restricted network egress to avoid SSRF to internal hosts.
Performance: launching Chromium per call is slow. On a server, launch Puppeteer once and reuse it:
import puppeteer from "puppeteer";
const browser = await puppeteer.launch();
const pdf = await kundliDetailedPdf(report, { branding, browser }); // browser not closed for youOn serverless (AWS Lambda etc.), inject puppeteer-core + a Chromium layer:
import chromium from "@sparticuz/chromium";
import puppeteer from "puppeteer-core";
const browser = await puppeteer.launch({ executablePath: await chromium.executablePath(), args: chromium.args });
const pdf = await horoscopePdf(report, { browser });Covered reports: kundliLite, kundliDetailed, kundliBrihad, matchMaking,
dashaAnalysis, numerology, sadeSati, varshaphal, horoscope
(each has both a render*Html and a *Pdf form). All render in en/hi/mr
(and other locales where the report data carries them); Chromium's bundled
Noto fonts handle every Indic script.
Contributing
The typed surface is generated from a manifest. After editing
scripts/endpoints_part*.json, regenerate and build:
npm run generate # regenerate src/resources/*
npm run typecheck
npm run build
npm testLicense
MIT © DivyGuru
