To stream natural-language astrology answers, send a POST request to /api/v1/astrology/query/stream with a question and birth details, and read the response as a Server-Sent Events (SSE) stream. You receive the answer incrementally as it is generated, then a final event carrying the complete text and billing metadata. The request body is identical to the blocking /api/v1/astrology/query endpoint, so you can switch transports without reshaping your payload.
This guide walks through the endpoint, the event shapes you will parse, working client code in JavaScript and Python, and the error and cancellation cases that matter in production. Everything here uses the real Vedika endpoint contracts so you can copy, adapt, and ship.
Why stream an astrology answer at all
A computed chart is fast. The natural-language interpretation that turns that chart into a paragraph a person can read is where the wall-clock time goes. If you wait for the entire interpretation before painting anything, a user staring at a chat box sees a spinner for the full duration. Streaming flips that: the first words land in a fraction of the total time, and the rest arrive token by token while the reader is already engaged.
Server-Sent Events is the right tool for this shape of problem. It is one-directional (server to client), runs over plain HTTP, reconnects on its own in browsers, and needs no extra protocol negotiation the way WebSockets do. For an astrology answer — a single request that produces a single growing block of text — SSE is simpler to operate and easier to debug than a bidirectional socket.
When to prefer the non-streaming endpoint
Streaming is not always the right call. If you are running a nightly batch that generates reports, populating a cache, or responding to a webhook where nothing is rendered live, use /api/v1/astrology/query and take the single JSON object. It is one round trip, one parse, no event loop. Reserve streaming for the cases where a human is watching the text appear.
The request: same body, different transport
Both the blocking and streaming endpoints accept the same JSON. You pass the user's question and a birthDetails object. The optional speed: "fast" flag routes the request through the lower-latency path (available on plans that include the fast path).
curl -N -X POST https://api.vedika.io/api/v1/astrology/query/stream \
-H "x-api-key: vk_live_your_key_here" \
-H "Content-Type: application/json" \
-H "Accept: text/event-stream" \
-d '{
"question": "What does my chart say about my career direction this year?",
"birthDetails": {
"datetime": "1990-08-15T14:30:00",
"latitude": 18.5204,
"longitude": 73.8567,
"timezone": "Asia/Kolkata"
},
"speed": "fast"
}'
The -N flag disables curl's output buffering so you watch events arrive in real time. The Accept: text/event-stream header signals that you want the SSE response rather than a single JSON body.
Birth details, precisely
| Field | Type | Notes |
|---|---|---|
datetime | string | Local civil time at the birthplace, ISO 8601, no offset suffix. |
latitude | number | Decimal degrees, north positive. |
longitude | number | Decimal degrees, east positive. |
timezone | string | IANA name (for example Asia/Kolkata). This resolves the local datetime to the correct instant — get it wrong and the ascendant shifts. |
The chart math underneath is computed by the XALEN Ephemeris, Vedika's own open-source astronomical engine, validated against JPL DE440 and swetest across millions of test charts. That precision is astronomical — planet and angle positions — and it means the interpretation you stream is built on a correctly placed chart, not an approximation.
The event stream: what you parse
An SSE response is a sequence of text records separated by blank lines. Each record can carry an event: type and a data: payload. A typical Vedika stream looks like this on the wire:
event: token
data: {"text": "Your tenth house"}
event: token
data: {"text": " lord is well placed,"}
event: token
data: {"text": " supporting steady career growth."}
event: done
data: {"answer": "Your tenth house lord is well placed, supporting steady career growth.", "usage": {"cost": 0.03, "currency": "USD"}}
Two event types matter for most integrations:
token— an incremental chunk of the answer. Append thetextfield to whatever you are rendering.done— the terminal event. It carries the fullanswer(so you can persist it without reassembling chunks) and ausageblock with the billed cost. When you see this, the stream is finished and the connection closes.
If something goes wrong mid-stream, an error event arrives with a message and the connection closes. Always handle it — a half-rendered answer that silently stalls is worse than a clear error.
A browser and Node client in JavaScript
The built-in EventSource API only does GET requests, so for a POST stream you read the response body yourself with fetch and a stream reader. This works in modern browsers and in server-side JavaScript runtimes alike.
async function streamAnswer(question, birthDetails, onToken) {
const controller = new AbortController();
const res = await fetch("https://api.vedika.io/api/v1/astrology/query/stream", {
method: "POST",
headers: {
"x-api-key": process.env.VEDIKA_API_KEY,
"Content-Type": "application/json",
"Accept": "text/event-stream",
},
body: JSON.stringify({ question, birthDetails, speed: "fast" }),
signal: controller.signal,
});
if (!res.ok) {
throw new Error(`Stream failed: ${res.status} ${await res.text()}`);
}
const reader = res.body.getReader();
const decoder = new TextDecoder();
let buffer = "";
let finalAnswer = "";
while (true) {
const { value, done } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
// SSE records are separated by a blank line.
const records = buffer.split("\n\n");
buffer = records.pop(); // keep the incomplete tail
for (const record of records) {
const eventMatch = record.match(/^event: (.+)$/m);
const dataMatch = record.match(/^data: (.+)$/m);
if (!dataMatch) continue;
const type = eventMatch ? eventMatch[1] : "message";
const payload = JSON.parse(dataMatch[1]);
if (type === "token") {
finalAnswer += payload.text;
onToken(payload.text);
} else if (type === "done") {
return payload.answer || finalAnswer;
} else if (type === "error") {
throw new Error(payload.message || "stream error");
}
}
}
return finalAnswer;
}
// Usage:
streamAnswer(
"Is this a good year to change jobs?",
{
datetime: "1990-08-15T14:30:00",
latitude: 18.5204,
longitude: 73.8567,
timezone: "Asia/Kolkata",
},
(chunk) => process.stdout.write(chunk)
).then((answer) => console.log("\n\nDone:", answer.length, "chars"));
Buffering matters here. Network chunks do not align to SSE record boundaries, so you accumulate bytes and only process complete records (everything before the last blank-line split). The trailing fragment stays in the buffer until the next read completes it.
A Python client
In Python, the httpx library streams the response line by line cleanly. The same record-buffering idea applies, but iterating lines keeps it readable.
import json
import os
import httpx
def stream_answer(question, birth_details, on_token):
payload = {
"question": question,
"birthDetails": birth_details,
"speed": "fast",
}
headers = {
"x-api-key": os.environ["VEDIKA_API_KEY"],
"Content-Type": "application/json",
"Accept": "text/event-stream",
}
final_answer = ""
with httpx.stream(
"POST",
"https://api.vedika.io/api/v1/astrology/query/stream",
json=payload,
headers=headers,
timeout=60.0,
) as res:
res.raise_for_status()
event_type = "message"
for line in res.iter_lines():
if line.startswith("event: "):
event_type = line[len("event: "):]
elif line.startswith("data: "):
data = json.loads(line[len("data: "):])
if event_type == "token":
final_answer += data["text"]
on_token(data["text"])
elif event_type == "done":
return data.get("answer", final_answer)
elif event_type == "error":
raise RuntimeError(data.get("message", "stream error"))
return final_answer
if __name__ == "__main__":
answer = stream_answer(
"What should I focus on this year?",
{
"datetime": "1990-08-15T14:30:00",
"latitude": 18.5204,
"longitude": 73.8567,
"timezone": "Asia/Kolkata",
},
lambda chunk: print(chunk, end="", flush=True),
)
print("\n\nFinal length:", len(answer))
Errors, timeouts, and cancellation
A streaming connection has more failure surface than a single request, so handle these cases explicitly:
- Authentication. A bad or missing
vk_live_*key fails before any events stream, with a 401 status on the initial response. Checkres.ok(orraise_for_status) before you start reading the body. - Mid-stream errors. If interpretation fails after tokens have started, you receive an
errorevent. Surface it to the user rather than leaving a truncated answer on screen. - Client timeouts. Set a generous read timeout (60 seconds is comfortable). Idle-timeout logic on a streaming response should measure time since the last byte, not total elapsed time.
- Cancellation. Abort the request (an
AbortControllerin JavaScript, exiting thewithblock in Python) when the user navigates away. This frees the connection promptly.
When the stream ends normally with a done event, read the usage block to reconcile billing. Streaming and blocking requests bill at the same per-query rate, so cost reporting stays consistent regardless of transport.
Where streaming fits in the wider API
The streaming endpoint is one natural-language surface among 700+ operations across 25 domains. If you need the raw chart rather than prose, the V2 computation endpoints under /v2/astrology/* accept flat datetime, latitude, longitude, and timezone parameters and return structured JSON. The same key serves Vedic (sidereal), Western (tropical), and KP from one account, plus Jaimini, Tajaka, Lal Kitab, and numerology, in 30 languages.
Every astrological reading the stream produces is grounded in classical sources actually used in Jyotish, KP, and Western practice — texts such as Brihat Parashara Hora Shastra, Phaladeepika, and Ptolemy's Tetrabiblos — so the prose you render is traceable rather than invented.
Key facts
- Streaming endpoint:
POST /api/v1/astrology/query/stream, response typetext/event-stream. - Request body is identical to the blocking
POST /api/v1/astrology/queryendpoint. - Event types:
token(incremental text),done(full answer plus usage),error(failure with message). - Authentication header:
x-api-key: vk_live_*. Base URL:https://api.vedika.io. - Streaming bills the same per-query rate as blocking, typically $0.01 to $0.05.
- Chart math runs on the XALEN Ephemeris, validated against JPL DE440 and swetest.
Try it
You can exercise the request and response shapes for free in the sandbox with no key required, then read the full contract in the docs. When you are ready for live keys, the pricing page lays out the per-query rates and plan paths, and the astrology API quickstart covers your first blocking request end to end.
FAQ
What is the streaming endpoint for the Vedika astrology API?
Stream natural-language answers from POST /api/v1/astrology/query/stream. It accepts the same JSON body as the non-streaming /api/v1/astrology/query endpoint and returns a Server-Sent Events stream of incremental tokens, ending with a final event that carries the complete answer and billing metadata.
Do I get charged differently for streaming versus a single response?
No. Streaming bills the same per-query rate as the blocking endpoint. The cost is for the answer, not the transport. You can test the shapes for free in the sandbox without a key.
Can I cancel a streaming astrology request mid-answer?
Yes. Aborting the request on the client stops the stream. Billing reflects the work completed; check the final event metadata when the stream finishes normally.
Should I use streaming or the standard query endpoint?
Use streaming when a human watches the answer appear, such as a chat UI, because perceived latency drops sharply. Use the standard endpoint for batch jobs, webhooks, or anywhere you only need the final text.