:::note
**TL;DR**
- One TypeScript SDK covers Western astrology, Vedic kundli, panchang, tarot, numerology, biorhythm, I Ching, crystals, dreams, and angel numbers.
- Install with `npm install @roxyapi/sdk` or `bun add @roxyapi/sdk`. Every method returns `{ data, error, response }` so you never throw in a hot request path.
- Geocode the birth city with `roxy.location.searchCities` first. Pass the returned `utcOffset` (a decimal) as the `timezone` number on chart endpoints.
- Build a daily horoscope, a Vedic birth chart, and a tarot spread in under 30 minutes with [`@roxyapi/sdk`](https://www.npmjs.com/package/@roxyapi/sdk).
:::

**About the author:** Brett Calloway is a Developer Advocate and AI Integration Specialist with 12 years of experience building APIs and developer tooling. He has led developer relations at two Series B SaaS companies and spoken at PyCon and JSConf on building context-rich AI agents using Model Context Protocol.

## Why Node.js developers stall when building insight apps

Every astrology, tarot, or numerology side project starts with the same blocker: the math. Natal chart calculations need an ephemeris verified against authoritative sources. Vedic panchang needs sunrise and tithi math. KP needs sub-lord theory. Tarot needs a seeded RNG that produces the same card per user per day. Most Node.js developers spend a weekend piecing together unrelated npm packages, a tarot deck JSON, and three timezone workarounds, then ship a broken V1. The problem is not Node, the problem is stitching four single-purpose libraries together and reinventing every interpretation string yourself. The [Roxy TypeScript SDK](/products/astrology-api "production-ready TypeScript SDK for astrology, Vedic, tarot, and more") collapses twelve spiritual-data domains behind one import. Calculations are verified against NASA JPL Horizons, interpretations ship in eight languages. This post walks through the three patterns that matter: geocode, compute, interpret.

## Install and authenticate in two minutes

Pick your package manager. The SDK is pure TypeScript with zero runtime dependencies beyond the built-in `fetch`, so it installs in seconds on Node 20+, Bun, Deno, Cloudflare Workers, and Vercel Edge.

```bash
# npm
npm install @roxyapi/sdk

# or bun (recommended for monorepos)
bun add @roxyapi/sdk

# pnpm / yarn also work
pnpm add @roxyapi/sdk
yarn add @roxyapi/sdk
```

Get an API key at [pricing](/pricing "RoxyAPI pricing and plan tiers"). Starter is $39 a month for 25,000 requests across every domain with one key. Every endpoint uses the same `X-API-Key` header, and `createRoxy` injects it automatically.

```typescript
import { createRoxy } from '@roxyapi/sdk';

const roxy = createRoxy(process.env.ROXY_API_KEY!);

// A first call. Typed response, no manual JSON parsing.
const { data } = await roxy.astrology.getDailyHoroscope({
  path: { sign: 'aries' },
});
console.log(data?.overview);
```

The SDK sends `X-SDK-Client: roxy-sdk-typescript/1.x.x` on every request so you can track SDK usage in your own logs. Every response is fully typed, your IDE shows request params and response fields without opening the docs.

## Geocode the birth city before any chart call

Chart endpoints (natal, Vedic, synastry, panchang, KP, transits, compatibility) need `latitude`, `longitude`, and `timezone` as a **decimal number**. Never ask the user to type coordinates. Geocode the city first, then pass the result into the chart method.

The location response is a paginated envelope. Each city has two timezone fields: `timezone` is the IANA identifier (`Asia/Kolkata`) for your date library, and `utcOffset` is the DST-adjusted decimal (`5.5` for IST, `-5` for EST, `9` for JST). Pass `utcOffset` to chart endpoints.

```typescript
const { data } = await roxy.location.searchCities({
  query: { q: 'Mumbai, India' },
});

// data = { total, limit, offset, cities: [{
//   city: 'Mumbai', latitude: 19.017, longitude: 72.857,
//   timezone: 'Asia/Kolkata', utcOffset: 5.5, ...
// }] }

const { latitude, longitude, utcOffset } = data!.cities[0];

const { data: natal } = await roxy.astrology.generateNatalChart({
  body: {
    date: '1990-01-15',
    time: '14:30:00',
    latitude,
    longitude,
    timezone: utcOffset,
  },
});
```

Passing the IANA string instead of the decimal returns `validation_error: expected number, received string`. This is the single most common mistake and the SDK AGENTS.md flags it in red for AI coding agents.

## Build a daily horoscope endpoint in three lines

The daily horoscope endpoint is the cheapest hook in any consumer app. It drives daily active users, push notifications, and streaks. One GET call, no body, no coordinates.

```typescript
const { data } = await roxy.astrology.getDailyHoroscope({
  path: { sign: 'scorpio' },
});

// data is typed, every field autocompletes in your IDE
console.log(data!.overview);         // General daily forecast, ~230 chars
console.log(data!.love);              // Love and relationship forecast
console.log(data!.career);            // Career outlook
console.log(data!.health);            // Health advice
console.log(data!.finance);           // Finance outlook
console.log(data!.luckyNumber);       // number
console.log(data!.luckyColor);        // string
console.log(data!.compatibleSigns);   // string[]
console.log(data!.moonPhase);         // Current moon phase name
console.log(data!.energyRating);      // 1 to 10
```

Weekly (`getWeeklyHoroscope`) and monthly (`getMonthlyHoroscope`) variants return the same shape plus `luckyDays[]` and `keyDates[]`. For caching, the horoscope changes at midnight UTC, so a 1-day TTL works. See the [Western astrology reference](/api-reference#tag/western-astrology "full Western astrology endpoint reference with request and response schemas") for every field.

Ready to ship? [Get your API key](/pricing "RoxyAPI pricing, get your key in 60 seconds") and drop a daily-horoscope card into your app this afternoon.

## Generate a Vedic kundli and panchang

Vedic is where the depth shows. The kundli endpoint returns all twelve rashi houses with the planets placed in each, a `meta` dict keyed by planet name, house interpretations, and combustion / planetary-war metadata.

```typescript
const { data: kundli } = await roxy.vedicAstrology.generateBirthChart({
  body: {
    date: '1990-01-15',
    time: '14:30:00',
    latitude: 28.6139,
    longitude: 77.209,
    timezone: 5.5,
  },
});

// Iterate rashis for the 12-sign chart view
const rashis = ['aries', 'taurus', 'gemini', 'cancer', 'leo', 'virgo',
                'libra', 'scorpio', 'sagittarius', 'capricorn', 'aquarius', 'pisces'] as const;

for (const rashi of rashis) {
  const signs = kundli![rashi].signs; // planets in this rashi (can be empty)
  if (signs.length > 0) {
    console.log(rashi, signs.map(p => p.graha));
  }
}

// Or look up any planet directly via the meta lookup
console.log(kundli!.meta.Sun.rashi);            // e.g. "Capricorn"
console.log(kundli!.meta.Moon.nakshatra.name);   // e.g. "Uttara Ashadha"
```

Panchang is the other India-market staple. One call returns tithi, nakshatra, yoga, karana, rahu kaal, abhijit muhurta, gulika, and brahma muhurta for any date and location. See the [Vedic astrology API](/products/vedic-astrology-api "production-ready Vedic astrology API with kundli, panchang, dashas, and KP") product page for the full endpoint list.

## Cast a tarot spread with a deterministic seed

Tarot readings need a seeded RNG so the same user gets the same card on the same day. The SDK handles the seed automatically. Pass a user ID or session ID and the card is stable until tomorrow.

```typescript
// Daily card, same answer for this user until midnight
const { data: card } = await roxy.tarot.getDailyCard({ body: { seed: 'user-42' } });
console.log(card!.card.name);          // e.g. "The Star"
console.log(card!.card.imageUrl);      // Full-res card art URL
console.log(card!.card.reversed);      // bool, reversed meaning applies
console.log(card!.dailyMessage);       // Contextual message for today

// Ten-position Celtic Cross for a specific question
const { data: reading } = await roxy.tarot.castCelticCross({
  body: { question: 'What should I focus on this quarter?', seed: 'user-42-q1' },
});
for (const p of reading!.positions) {
  console.log(p.position, p.name, p.card.name, '-', p.interpretation);
}

// Lightweight yes / no for an impulse feature
const { data: yn } = await roxy.tarot.castYesNo({ body: { question: 'Should I take the offer?' } });
console.log(yn!.answer);     // "Yes" | "No" | "Maybe"
console.log(yn!.strength);    // "Strong" | "Qualified"
console.log(yn!.card.name);
```

Card art ships as public HTTPS URLs, no signed-URL dance, safe to embed directly in React or Next.js Image components. The full [tarot API reference](/api-reference#tag/tarot "full tarot API reference with spread schemas and card catalog") has 10 endpoints including three-card, love spread, and the 78-card catalog.

## Handle errors without throwing

The TypeScript SDK returns `{ data, error, response }` from every method. `data` and `error` are mutually exclusive, so branches never overlap. No try / catch in your hot path, no surprise throws, just a tagged union you can narrow.

```typescript
const { data, error } = await roxy.astrology.getDailyHoroscope({
  path: { sign: 'scorpio' },
});

if (error) {
  switch (error.code) {
    case 'validation_error':
      console.error('Bad input:', error.error);
      break;
    case 'rate_limit_exceeded':
      console.error('Monthly quota reached, retry on the 1st');
      break;
    case 'subscription_inactive':
    case 'invalid_api_key':
      console.error('Auth problem:', error.code);
      break;
    default:
      console.error('API error:', error.code, error.error);
  }
  return;
}

// data is now non-null, TypeScript narrows automatically
console.log(data.overview);
```

Validation errors include an `issues[]` array with the specific field path that failed. No more guessing which parameter your integration sent wrong. The canonical error code list lives on the [SDK docs page](/docs/sdk "RoxyAPI Python and TypeScript SDK docs, quickstart, and reference").

## Deploy with Next.js, Express, or Hono

The SDK works anywhere `fetch` exists: Node 20+, Bun, Deno, Cloudflare Workers, Vercel Edge, Next.js server actions, Express, Hono, Fastify, Koa. Zero framework lock-in.

```typescript
// Next.js 15 App Router route handler
// app/api/horoscope/[sign]/route.ts
import { createRoxy } from '@roxyapi/sdk';

const roxy = createRoxy(process.env.ROXY_API_KEY!);

export async function GET(
  _req: Request,
  { params }: { params: Promise<{ sign: string }> },
) {
  const { sign } = await params;
  const { data, error } = await roxy.astrology.getDailyHoroscope({ path: { sign } });
  return error
    ? Response.json({ error: error.code }, { status: 400 })
    : Response.json(data);
}
```

```typescript
// Hono on Cloudflare Workers or Bun
import { Hono } from 'hono';
import { createRoxy } from '@roxyapi/sdk';

const app = new Hono();

app.post('/natal', async (c) => {
  const { city, date, time } = await c.req.json();
  const roxy = createRoxy(c.env.ROXY_API_KEY);

  const { data: locations } = await roxy.location.searchCities({ query: { q: city } });
  const { latitude, longitude, utcOffset } = locations!.cities[0];

  const { data, error } = await roxy.astrology.generateNatalChart({
    body: { date, time, latitude, longitude, timezone: utcOffset },
  });
  return error ? c.json({ error }, 400) : c.json(data);
});

export default app;
```

The SDK uses the platform `fetch` directly, so connection reuse, HTTP/2, and edge-native streaming all work automatically. Benchmarks on a Hetzner CX23 show median end-to-end latency of 87 ms for the horoscope endpoint and 180 ms for a full natal chart, including the round trip from Frankfurt to the API.

## Give your AI agents the same SDK your code uses

Node.js insight apps are a natural fit for Claude Code, Cursor, Windsurf, and the OpenAI Agents SDK because the data they return is structured JSON, not prose. The Roxy TypeScript SDK ships an `AGENTS.md` inside the npm package at `node_modules/@roxyapi/sdk/AGENTS.md`, so any AI coding agent that reads `AGENTS.md` (Claude Code, Cursor, Windsurf, Copilot, Codex, Gemini CLI) picks up the critical patterns automatically: geocode first, timezone is a decimal, location returns an envelope, method names come from `operationId`, not URL paths. Separately, each domain exposes a remote MCP server at `https://roxyapi.com/mcp/{domain}` (Streamable HTTP, no stdio, no self-hosting) so agents can call the API directly without glue code. Read the [MCP setup guide](/docs/mcp "RoxyAPI MCP server setup, authentication, and tool naming") to wire up Claude Desktop or Cursor in under five minutes.

## Troubleshooting checklist for the first hour

These are the five issues every new integrator hits. Work through them once and you will not hit them again.

First, the `timezone` parameter must be a decimal number. `"Asia/Kolkata"` fails with `validation_error: expected number, received string`. Use `city.utcOffset`, not `city.timezone`. Second, `time` must include seconds in `HH:MM:SS` format, `14:30` fails. Third, parameters are structured: always `{ path: {...} }`, `{ body: {...} }`, or `{ query: {...} }`, never flat. Fourth, location responses are paginated envelopes, always index `data.cities[0]`, never `data[0]`. Fifth, do not expose `ROXY_API_KEY` client-side. Call from server components, route handlers, server actions, or edge functions only. If you hit `invalid_api_key` with a correct key, check for a trailing newline or stray whitespace in your env file.

## Frequently Asked Questions

**Q: What does the Roxy TypeScript SDK cover?**
A: Twelve spiritual-data domains behind one key. Western astrology, Vedic or Jyotish, numerology, tarot, biorhythm, I Ching, crystals, dreams, angel numbers, and location. Plus usage stats. A single `npm install @roxyapi/sdk` gets every domain, no stitching needed.

**Q: Is the SDK fully typed?**
A: Yes, every request body, path param, query param, and response shape is a TypeScript type generated from the OpenAPI spec. Your IDE autocompletes every domain, every method, every field. No manual type definitions, no `@types/*` dependency.

**Q: Why does the timezone field on a city return Asia Kolkata instead of a number?**
A: The city `timezone` field is the IANA identifier for date libraries like Luxon and day.js. Chart endpoints need a decimal like 5.5. Use the `utcOffset` field on the same city (already DST-adjusted) and pass it as the `timezone` value on chart requests.

**Q: Can I run the SDK on Cloudflare Workers or Vercel Edge?**
A: Yes. The SDK depends only on the platform `fetch` API, so it runs on Node 20+, Bun, Deno, Cloudflare Workers, Vercel Edge, and browser service workers (server-side only). No Node-specific polyfills required.

**Q: How do I avoid hitting the monthly quota during development?**
A: Keep the API key out of browser-exposed code and cache deterministic responses locally. Daily horoscopes, tarot daily cards, and angel number lookups are stable within a day, so a 1-day cache is safe. Use the free `roxy.usage.getUsageStats()` call to monitor quota in CI or a status endpoint.

## Conclusion

Node.js developers stall on insight apps because the math and the content are both hard. The Roxy TypeScript SDK removes both layers: one import, twelve domains, typed responses, framework-agnostic. Start with the [TypeScript SDK quickstart](/docs/sdk "RoxyAPI Python and TypeScript SDK docs, quickstart, and reference"), then pick the domain your users want first. [Pricing](/pricing "RoxyAPI pricing and plan tiers") starts at $39 a month for 25,000 requests across every endpoint, so your V1 costs less than a domain name.