app.asktian.com — api.asktian.com Integration Guide

Version: v3.24.0 / SDK v2.0.0
Date: April 8, 2026
Audience: app.asktian.com backend and frontend engineers
API base URL: https://api.asktian.com


Table of Contents

  1. Quick-Start Checklist
  2. Authentication
  3. Fixing the Core Integration Bugs
  4. Pattern Profile — tian.global
  5. SSE Streaming — v3.24.0 Contract
  6. Decision Guidance Fan-out
  7. Daily Anchor Card
  8. Compatibility Features
  9. Almanac and Divination Lots
  10. SDK v2.0.0 Reference
  11. Error Handling
  12. Rate Limits and Caching
  13. Roadmap Items

1. Quick-Start Checklist

Before writing any code, complete these steps in order. Each item unblocks the next.

StepActionWho
1Receive Enterprise API key (at_live_*) from [email protected]API team
2Set ASKTIAN_API_KEY=at_live_xxxx in the app's server environmentApp backend
3Add Authorization: Bearer header to all API calls in asktian-api.tsApp backend
4Fix tian.global endpoint path and parameter names (see §3)App backend
5Remove surname, givenName, luckyNumber from required onboarding fieldsApp frontend
6Replace custom fan-out with native SSE streaming (see §5)App backend
7Consume done.blendedScore, done.traditionScores, done.creditsUsed from SSE done eventApp frontend

Steps 3–7 require no API changes and can be completed immediately once the key is provisioned.


2. Authentication

All API calls must include an Authorization header with a Bearer token. The token is the app's Enterprise API key. It must be stored in the server environment and never exposed to the browser.

# Correct — server-side call
curl https://api.asktian.com/api/trpc/tian.global \
  -H "Authorization: Bearer at_live_xxxx" \
  -G --data-urlencode 'input={"json":{"birthdate":"1983-08-03","birthTime":"22:05"}}'
// asktian-api.ts — add to every fetch call
const headers = {
  "Authorization": `Bearer ${process.env.ASKTIAN_API_KEY}`,
  "Content-Type": "application/json",
};

The app should use the app-level Enterprise key for all calls, with TIAN Points deducted from the app's account. Per-user billing via privyToken is on the roadmap for a future release.


3. Fixing the Core Integration Bugs

The current asktian-api.ts has three bugs that cause all API calls to fail. None require API changes — they are all frontend fixes.

Bug 1: Wrong endpoint path

The app calls https://api.asktian.com/tian.global — this is missing the /api/trpc/ prefix.

// Wrong
const url = `https://api.asktian.com/tian.global?dob=...`;

// Correct
const url = `https://api.asktian.com/api/trpc/tian.global`;

All tRPC endpoints follow the pattern /api/trpc/{procedure}. The SSE streaming endpoints follow /api/stream/tian/{tradition}.

Bug 2: Wrong parameter names

The app uses dob, tob, and city — none of these are valid parameter names.

App uses (wrong)API expects (correct)Notes
dobbirthdateFormat: YYYY-MM-DD
tobbirthTimeFormat: HH:MM (e.g. "22:05")
citybirthPlaceOptional city string
gendergenderSame — "male" or "female"

Bug 3: Missing Authorization header

Covered in §2. Without the header, all requests return HTML error pages.

Bug 4: Treating optional params as required

surname, givenName, and luckyNumber are optional on all TIAN Blended endpoints. When omitted, the Name Analysis and Auspicious Number sub-systems are skipped and the credit cost is reduced. The minimum valid call requires only birthdate.

// Minimum valid call — works for all global users
const result = await client.tian.global({
  birthdate: "1983-08-03",
  question: "What is my cross-civilizational pattern?",
});

// Full call for users who provide Chinese name and lucky number
const result = await client.tian.global({
  birthdate: "1983-08-03",
  birthTime: "22:05",
  fullName: "Douglas Gan",
  surname: "陈",
  givenName: "志明",
  luckyNumber: "88",
  question: "What is my cross-civilizational pattern?",
});

4. Pattern Profile — tian.global

The tian.global endpoint is the primary call for onboarding. It runs all 29 divination systems across 5 traditions and returns a cross-civilizational Pattern Profile. This should be called once during onboarding and the result stored in the database with a 30-day TTL.

Correct call format

GET /api/trpc/tian.global?input={"json":{
  "birthdate": "1983-08-03",
  "birthTime": "22:05",
  "fullName": "Douglas Gan",
  "question": "What is my cross-civilizational pattern?"
}}
Authorization: Bearer at_live_xxxx

Response shape

The response includes all 29 tradition sub-results plus two enriched profile objects:

FieldTypeDescription
blendedScorenumberOverall cross-civilizational score (0–100)
synthesisstringLLM-generated cross-tradition synthesis
traditionScoresobjectScore per tradition group
signProfileTianGlobalSignProfileWestern sign data: westernSign, mantra, majorArcana
compatProfileTianGlobalCompatProfileChinese compat data: chineseAnimal, partnerAnimal, loveDimensionLabel
creditsUsednumberTIAN Points consumed (typically 29)

Note: The signProfile on tian.global returns only 3 fields (westernSign, mantra, majorArcana). For the full 9-field Western sign profile including Medical Astrology, call horoscope.calculate separately and use the HoroscopeSignProfile interface from SDK v2.0.0.

Storing the Pattern Profile

// Store in pattern_profiles table after onboarding
await db.patternProfiles.upsert({
  userId: user.id,
  tianGlobalResult: JSON.stringify(result),
  signProfile: result.signProfile,
  compatProfile: result.compatProfile,
  blendedScore: result.blendedScore,
  expiresAt: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000), // 30-day TTL
});

5. SSE Streaming — v3.24.0 Contract

The native SSE streaming endpoint is the correct approach for decision guidance. The app should replace its custom fan-out (executeGuidanceFanOut) with a direct call to the SSE stream.

Endpoint

GET /api/stream/tian/global
Authorization: Bearer at_live_xxxx

Query parameters

ParameterRequiredDescription
birthdateYesUser's birth date (YYYY-MM-DD)
birthTimeNoUser's birth time (HH:MM)
questionYesThe decision question
fullNameNoUser's full name (improves synthesis quality)

Complete event sequence (v3.24.0)

Every tian.global stream emits events in this order:

Event typeEmittedKey fieldsApp action
systemOnce per tradition (up to 29×)name, result, score, error?, tradition ✦, iconUrl ✦, systemSlugShow tradition card with icon; start animation
synthesis_startOnce, before first token ✦(no payload)Transition to synthesis reading phase
synthesis_chunkOne per LLM tokentextAppend token to synthesis display
doneOnce, after last tokenblendedScore, synthesis, traditionScores, creditsUsed, responseTimeMs, signProfile?, compatProfile?Show final score; store reading in DB
errorOn failurecode, messageShow error toast; allow retry

✦ New in v3.24.0

New fields on system events (v3.24.0)

The three new fields on system events eliminate the need for a separate catalogue lookup during the theatrical animation phase:

FieldTypeExampleUse
traditionstring"eastern"Map to tradition-specific animation
iconUrlstring"https://cdn.../qimen-icon.png"Show tradition icon immediately
systemSlugstring"qimen"Match against icon pack and system catalogue

Tradition to animation mapping

tradition valueSystems includedSuggested animation
easternQimen, BaZi, Zi Wei, I Ching, Feng Shui, Mahabote, 十二宮 …Hexagram spin / trigram reveal
westernTarot, Numerology, Runes, Astrology, Horoscope …Planetary orbit / card flip
africanIfá, Vodun, HakataShimmer pulse / cowrie scatter
islamicRammal, Khatt al-RamlGeometric pattern unfold
indianJyotish, Anka ShastraMandala bloom

App event type alignment

The app's internal event names differ from the API SSE event types. This table maps them directly:

App event (internal)API eventNotes
tradition_start(none)Use synthesis_start as the phase-transition signal
tradition_resultsystemsystem.tradition + system.iconUrl + system.systemSlug added in v3.24.0
tradition_complete(none)Use done as the all-traditions-complete signal
synthesis_startsynthesis_startDirect 1:1 mapping — new in v3.24.0
synthesis_chunksynthesis_chunkDirect 1:1 mapping
synthesis_completedoneFull synthesis text in done.synthesis
errorerrorDirect 1:1 mapping

TypeScript consumer (v3.24.0)

import { AskTianClient } from "asktian-sdk"; // npm install [email protected]

const client = new AskTianClient({ apiKey: process.env.ASKTIAN_API_KEY! });

for await (const chunk of client.tian.global.stream({
  birthdate: user.birthdate,
  birthTime: user.birthTime,
  question: req.body.question,
  fullName: user.fullName,
})) {
  if (chunk.type === "system") {
    // v3.24.0: tradition, iconUrl, systemSlug are now available
    // Send to frontend via your own SSE proxy
    res.write(`data: ${JSON.stringify({
      type: "tradition_result",
      name: chunk.name,
      score: chunk.score,
      tradition: chunk.tradition,   // "eastern" | "western" | "african" | "islamic" | "indian"
      iconUrl: chunk.iconUrl,        // CDN URL for tradition icon
      systemSlug: chunk.systemSlug,  // e.g. "qimen", "tarot", "ifa"
    })}\n\n`);
  }

  if (chunk.type === "synthesis_start") {
    // v3.24.0: signal the frontend to transition UI phases
    res.write(`data: ${JSON.stringify({ type: "synthesis_start" })}\n\n`);
  }

  if (chunk.type === "synthesis_chunk") {
    res.write(`data: ${JSON.stringify({ type: "synthesis_chunk", text: chunk.text })}\n\n`);
  }

  if (chunk.type === "done") {
    // Store reading in DB, then signal completion
    await db.readings.create({ userId, blendedScore: chunk.blendedScore, synthesis: chunk.synthesis });
    res.write(`data: ${JSON.stringify({ type: "synthesis_complete", blendedScore: chunk.blendedScore })}\n\n`);
    res.end();
  }

  if (chunk.type === "error") {
    res.write(`data: ${JSON.stringify({ type: "error", code: chunk.code, message: chunk.message })}\n\n`);
    res.end();
  }
}

6. Decision Guidance Fan-out

The app's current executeGuidanceFanOut function calls individual endpoints in parallel and runs its own LLM synthesis. This duplicates what the TIAN Blended SSE streaming already does natively and costs more TIAN Points.

Recommended approach: replace the fan-out with a single tian.global stream call (§5). This gives you all 29 tradition results, the LLM synthesis, and the enriched profile data in one call at a fixed cost.

If you need to call individual endpoints for specific features (e.g., showing a standalone Tarot reading), individual endpoints can be called in parallel without hitting the rate limit. A fan-out of 4–5 simultaneous calls is well within the 300 requests per 15-minute window.

Intent to endpoint mapping

For category-specific guidance, use the appropriate TIAN Blended endpoint rather than tian.global:

CategoryRecommended endpointRationale
Career / Financetian.easternQimen Dunjia timing, BaZi wealth pillar
Love / Relationshipstian.eastwestChinese zodiac + Western synastry
General / Spiritualtian.globalAll 5 traditions
Western-focused userstian.westernTarot, Numerology, Runes, Astrology
Indian traditiontian.indianJyotish, Anka Shastra

7. Daily Anchor Card

The Daily Pattern card is the primary daily engagement hook. The current API does not yet have a dedicated daily.anchor endpoint — this is under active evaluation for v3.24.0 API (target: April 2026). In the meantime, the app can compose the Daily Anchor from two existing calls.

Interim approach (available now)

// Call 1: Today's almanac (free, no birth data required)
const almanac = await client.almanac.daily({
  date: new Date().toISOString().split("T")[0], // "2026-04-08"
});

// Call 2: User's natal chart (cache this — it doesn't change)
const horoscope = await client.horoscope.calculate({
  birthdate: user.birthdate,
  birthHour: user.birthHour,
});

// Compose the Daily Anchor card from both responses
const dailyAnchor = {
  date: almanac.date,
  twelveValue: almanac.twelveValue,       // e.g. "成" (Achievement)
  deity: almanac.deity,                   // e.g. "青龍" (Azure Dragon)
  fortune: almanac.fortune,               // "good_fortune" | "neutral" | "caution"
  auspicious: almanac.auspiciousActivities,
  inauspicious: almanac.inauspiciousActivities,
  sunSign: horoscope.sunSign,             // User's sun sign
  mantra: horoscope.signProfile?.mantra,  // Sign mantra for daily focus
};

When daily.anchor is available (v3.24.0 API)

The dedicated endpoint will return a personalised daily message, lucky/avoid hours based on the user's BaZi day master, and a dominantTheme summarising the most significant current transit — all in a single call at 3 TIAN Points.


8. Compatibility Features

Chinese zodiac compatibility — compatibility.zodiac

Returns a score, level, description, and 5-dimension YouApp data for two Chinese zodiac animals.

import { ZodiacCompatResponse } from "asktian-sdk"; // v2.0.0

const result: ZodiacCompatResponse = await client.compatibility.zodiac({
  animal1: "rabbit",  // User's Chinese zodiac animal
  animal2: "dragon",  // Partner's Chinese zodiac animal
});

// result.score — 0–100
// result.level — "excellent" | "good" | "neutral" | "challenging"
// result.description — classical Chinese compatibility description
// result.dimensions.love.label — e.g. "Positive"
// result.dimensions.love.text — full dimension description
// result.dimensions.career / wealth / health / marriage — same shape

Birthday-based compatibility — compatibility.birthday

Returns Chinese 4D dimensions and Western 4D dimensions for two birth dates. This is the recommended endpoint for the Synastry Card feature.

import { BirthdayCompatResponse } from "asktian-sdk"; // v2.0.0

const result: BirthdayCompatResponse = await client.compatibility.birthday({
  birthDate1: "1983-08-03",
  birthDate2: "1990-05-15",
});

// result.score — overall compatibility score
// result.romanceScore / friendshipScore / marriageScore
// result.dimensions — Chinese 4D (love/career/wealth/health/marriage)
// result.horoscopeDimensions — Western 4D (love/career/wealth/health)

Zodiac sign profile — almanac.zodiacSign

Returns the full Western sign profile (Medical Astrology, Tarot, Mantra) and the 60-element Chinese zodiac profile.

import { AlmanacZodiacResponse } from "asktian-sdk"; // v2.0.0

const result: AlmanacZodiacResponse = await client.almanac.zodiacSign({
  birthDate: "1983-08-03",
});

// result.westernProfile.medical — Medical Astrology body system
// result.westernProfile.mantra — Sign mantra
// result.westernProfile.majorArcana — Tarot archetype
// result.chineseProfile — 60-element profile (personality, career, love, etc.)

9. Almanac and Divination Lots

Daily almanac — almanac.daily

Returns today's Chinese almanac data. In v3.24.0 API, a language parameter will be added to return English translations of auspiciousActivities and inauspiciousActivities.

const almanac = await client.almanac.daily({
  date: "2026-04-08",
  // language: "en" — available in v3.24.0 API
});

Divination lot drawing — divination.draw

The 42 lot systems with 2,901 lots are fully functional. In v3.24.0 API, a language parameter will be added for English interpretations.

const lot = await client.divination.draw({
  system: "guanyin",  // or any of the 42 lot systems
  // language: "en" — available in v3.24.0 API
  // dailySeed: user.birthdate — deterministic daily lot (under evaluation)
});

10. SDK v2.0.0 Reference

Install the latest SDK:

npm install [email protected]

New in v2.0.0 — response-shape interfaces

SDK v2.0.0 adds four typed interfaces for the full response objects of the 4 enriched endpoints. Use these to type your database storage and React props.

InterfaceEndpointKey fields
HoroscopeResponsehoroscope.calculatesunSign, moonSign, ascendant, elementProfile, placements, synthesis, signProfile?, creditsUsed
ZodiacCompatResponsecompatibility.zodiacscore, level, description, dimensions?
BirthdayCompatResponsecompatibility.birthdayscore, romanceScore, friendshipScore, marriageScore, dimensions?, horoscopeDimensions?
AlmanacZodiacResponsealmanac.zodiacSignwestern?, chinese?, chineseProfile?, westernProfile?

Existing interfaces (v1.7.0+)

InterfaceUsed for
HoroscopeSignProfilesignProfile on horoscope.calculate and almanac.zodiacSign
ChineseZodiacProfilechineseProfile on almanac.zodiacSign
ZodiacDimensionsdimensions on compatibility.zodiac and compatibility.birthday
HoroscopeDimensionshoroscopeDimensions on compatibility.birthday
TianGlobalSignProfilesignProfile on tian.global (3-field abbreviated version)
TianGlobalCompatProfilecompatProfile on tian.global
TianGlobalStreamChunkUnion type for for await loop on tian.global stream

Full TypeScript example with v2.0.0 types

import {
  AskTianClient,
  HoroscopeResponse,
  ZodiacCompatResponse,
  TianGlobalStreamChunk,
} from "asktian-sdk";

const client = new AskTianClient({ apiKey: process.env.ASKTIAN_API_KEY! });

// Typed horoscope response
const horoscope: HoroscopeResponse = await client.horoscope.calculate({
  birthdate: "1983-08-03",
  birthHour: 22,
});

// Typed compatibility response
const compat: ZodiacCompatResponse = await client.compatibility.zodiac({
  animal1: "rabbit",
  animal2: "dragon",
});

// Typed streaming
for await (const chunk of client.tian.global.stream({
  birthdate: "1983-08-03",
  question: "Should I change careers?",
}) as AsyncGenerator<TianGlobalStreamChunk>) {
  if (chunk.type === "done") {
    console.log(chunk.signProfile?.mantra);       // "I Use"
    console.log(chunk.compatProfile?.chineseAnimal); // "rabbit"
  }
}

11. Error Handling

All API errors return a consistent JSON envelope:

{
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Invalid or missing API key",
    "data": { "httpStatus": 401 }
  }
}

Common error codes:

CodeHTTP statusCauseAction
UNAUTHORIZED401Missing or invalid API keyCheck ASKTIAN_API_KEY env var
FORBIDDEN403Endpoint requires higher tierUpgrade to Enterprise for tian.global
TOO_MANY_REQUESTS429Rate limit exceededBack off and retry after X-RateLimit-Reset
INSUFFICIENT_CREDITS402Not enough TIAN PointsTop up the account
BAD_REQUEST400Invalid parametersCheck parameter names and formats
INTERNAL_SERVER_ERROR500API-side errorRetry with exponential backoff

Note: In v3.24.0 API, HTML error pages on 5xx responses will be replaced with the JSON envelope above. Until then, the app should handle non-JSON responses gracefully.

import { AskTianClient, AskTianError } from "asktian-sdk";

try {
  const result = await client.tian.global({ birthdate: "1983-08-03" });
} catch (err) {
  if (err instanceof AskTianError) {
    if (err.status === 429) {
      // Rate limited — retry after the reset window
      const resetAt = err.body?.data?.resetAt;
      await sleep(resetAt - Date.now());
    } else if (err.status === 402) {
      // Insufficient credits — notify the app owner
      await notifyOwner({ title: "TIAN Points low", content: err.message });
    }
  }
}

12. Rate Limits and Caching

Rate limit headers

All API responses include rate limit headers. The app's backend proxy should forward these to the frontend:

HeaderDescription
X-RateLimit-LimitMaximum requests per 15-minute window
X-RateLimit-RemainingRequests remaining in the current window
X-RateLimit-ResetUnix timestamp when the window resets

Recommended caching strategy

Caching is essential for keeping TIAN Points costs manageable. The following TTLs are recommended:

DataCache keyTTLNotes
tian.global resulttian:global:{userId}30 daysRefresh on significant life events
horoscope.calculatehoroscope:{birthdate}:{birthHour}90 daysNatal chart never changes
almanac.zodiacSignalmanac:zodiac:{birthDate}90 daysSign profile never changes
almanac.dailyalmanac:daily:{date}24 hoursOne almanac per day
compatibility.zodiaccompat:zodiac:{a1}:{a2}90 daysAnimal pair never changes
compatibility.birthdaycompat:birthday:{d1}:{d2}90 daysBirth date pair never changes
Decision guidance stream(do not cache)Each question is unique

13. Roadmap Items

The following features are not yet available in the API but are under active development. The app should design its data model to accommodate them when they land.

FeatureEndpointTargetNotes
Daily personalised readingdaily.anchorv3.24.0 APIAlmanac + natal chart + LLM synthesis in one call (3 TIAN Points)
Moon phase + retrograde statusalmanac.daily enhancementv3.24.0 APIWill be added as new fields to the existing endpoint
English almanac translationsalmanac.daily language paramv3.24.0 APIlanguage: "en"
English lot interpretationsdivination.draw language paramv3.24.0 APIlanguage: "en"
SSE synthesis_start eventtian.* streamv3.24.0 APIPhase-transition signal
SSE tradition, iconUrl, systemSlug on system eventstian.* streamv3.24.0 APIEliminates catalogue lookup during animation
BaZi standalone endpointbazi.calculatev3.25.0 APIFour Pillars, day master, 10-year luck cycle
Current transitsastrology.transitsv3.25.0+ APINatal chart cross-referenced against current ephemeris
Per-user billingprivyToken on TIAN BlendedTBDApp-level key recommended for launch

api.asktian.com Backend Team — April 8, 2026