Generate Report
POST https://starsapi.com/api/v2/reports/generate-report
Generates a white-labelled PDF report from birth details. One endpoint covers every report
type — the report_type field selects which one. The response carries a
stable download URL from the very first call.
Authentication
| Method | How |
|---|---|
| Header (recommended) | X-Api-Key: YOUR_KEY |
| Body | "api_key": "YOUR_KEY" |
Request body
Fields for single-chart reports (everything except kundli-matching):
| Field | Type | Required | Description |
|---|---|---|---|
report_type | string | Yes | Which report to generate — see available reports. |
person_name | string | Yes | Name printed on the cover and used throughout the text. |
gender | string | No | male or female. Defaults to male. |
year | integer | Yes | Birth year, e.g. 1990. |
month | integer | Yes | Birth month, 1–12. |
day | integer | Yes | Birth day of month. |
hour | integer | Yes | Birth hour, 24-hour clock. |
minute | integer | Yes | Birth minute. |
second | integer | No | Birth second. Defaults to 0. |
latitude | float | Yes | Birth latitude, e.g. 28.6139. |
longitude | float | Yes | Birth longitude, e.g. 77.2090. |
timezone | string | Yes | IANA timezone ID of the birth place, e.g. Asia/Kolkata. |
ayanamsa | string | No | Defaults to lahiri. |
brand_name | string | No | Overrides your saved brand for this report only. |
brand_tagline | string | No | Tagline under the brand name on the cover. |
brand_url | string | No | Website shown on the PDF. |
brand_logo_url | string | No | Public URL of your logo image. |
Two-chart reports
kundli-matching compares two charts, so instead of flat birth fields it takes two
nested objects, person1 and person2. Each object holds that person's
name, gender and birth details.
| Field | Type | Required | Description |
|---|---|---|---|
report_type | string | Yes | Set to kundli-matching. |
person1 | object | Yes | First person — name, gender and birth details. |
person2 | object | Yes | Second person, same shape. |
chart_style | string | No | north_indian (default) or south_indian. |
language | string | No | ISO 639-1 code. Defaults to en. |
ayanamsa | string | No | Defaults to lahiri. Applies to both charts. |
The person object
Both person1 and person2 take the same fields:
| Field | Type | Required | Description |
|---|---|---|---|
name | string | No | Used throughout the report text. Falls back to Bride / Groom if omitted. |
gender | string | Yes | male or female — decides which chart is treated as bride and which as groom. |
year | integer | Yes | Birth year. |
month | integer | Yes | Birth month, 1–12. |
day | integer | Yes | Birth day of month. |
hour | integer | Yes | Birth hour, 24-hour clock. |
minute | integer | Yes | Birth minute. |
second | integer | No | Defaults to 0. |
latitude | float | Yes | Birth latitude. |
longitude | float | Yes | Birth longitude. |
timezone | string | Yes | IANA timezone ID of the birth place, e.g. Asia/Kolkata. |
A complete two-chart request looks like this:
{
"report_type": "kundli-matching",
"chart_style": "north_indian",
"language": "en",
"person1": {
"name": "Priya Sharma",
"gender": "female",
"year": 1994, "month": 3, "day": 12,
"hour": 9, "minute": 15,
"latitude": 19.0760, "longitude": 72.8777,
"timezone": "Asia/Kolkata"
},
"person2": {
"name": "Arjun Mehta",
"gender": "male",
"year": 1991, "month": 11, "day": 4,
"hour": 21, "minute": 40,
"latitude": 28.6139, "longitude": 77.2090,
"timezone": "Asia/Kolkata"
}
}
The batch flow
Reports contain many AI-written sections, so a single request would take far too long. Instead each call processes a batch of sections and returns straight away:
- The first call creates the report and returns
status: "processing"along with thedownload_url. - Repeat the identical request — same body, same birth details — and each call picks up where the last one stopped.
- When every section is written the PDF is rendered and the response returns
status: "ready".
The download_url is the same string in every response. Store it after the first call and
show it to your user immediately — if they open it early they get a self-refreshing
“preparing” page rather than an error.
Calling again after a report is already ready simply returns the same URL. It is not
regenerated and you are not charged twice.
Each call returns as soon as the next batch is queued — the heavy work continues on our side after
the response is sent, so your request doesn't sit waiting. A typical report finishes in
two to three minutes of wall-clock time across the calls. The progress
object in each response (done, total, percent) is there to drive
a progress bar while your user waits.
Downloading the PDF
The download_url returned above is a normal link you can hand straight to your user.
What it serves depends on where the report has got to:
- Ready — streams the PDF file.
- Still building — shows a self-refreshing “preparing your report” page.
- Failed or expired — shows an explanatory page.
Checking status from code
Append &format=json to the download URL to get machine-readable status instead of a
page or a file. This is the cheaper way to poll — it doesn't do any report work, it just reports
where things stand.
GET https://starsapi.com/api/v2/reports/download.php?token=YOUR_TOKEN&format=json
When the report is ready:
{
"success": true,
"status": "ready",
"file_size": 2847193,
"person_name": "Ravi Kumar",
"download_count": 0,
"download_url": "https://starsapi.com/api/v2/reports/download.php?token=..."
}
Otherwise success is false and the HTTP code tells you what happened:
| HTTP | status | Meaning |
|---|---|---|
| 200 | ready | PDF is built and downloadable. |
| 202 | preparing | Still building — keep calling the generate endpoint. |
| 400 | invalid | Token is missing or malformed. |
| 404 | not_found | No report exists for that token. |
| 410 | expired | Link is older than its expiry window — generate a fresh report. |
| 500 | failed | Generation errored. The message field explains why. |
Link expiry
Download links stay valid for 7 days from creation. After that the URL returns
410 expired and the PDF is no longer served. If your users need long-term access, download
the file to your own storage while the link is live, or regenerate the report on demand.
Response shape
| Field | Type | Description |
|---|---|---|
success | boolean | true when the call was accepted. |
status | string | processing while sections remain, ready once the PDF exists. |
download_url | string | Hosted URL of the PDF. Stable from the first call onward. |
token | string | 64-character identifier for this report, also embedded in the download URL. |
message | string | Human-readable progress note, safe to show your user while they wait. |
progress | object | Present while processing: done, total and percent — ideal for a progress bar. |
person_name | string | Echoed back from the request. |
chart_hash | string | Fingerprint of the birth chart, used internally to detect repeat requests. |
time_ms | integer | How long this call took, in milliseconds. |
Once the PDF exists, the shape changes slightly — progress and message
drop away, and file details appear:
{
"success": true,
"status": "ready",
"download_url": "https://starsapi.com/api/v2/reports/download.php?token=...",
"token": "...",
"file_size": 2847193,
"person_name": "Ravi Kumar",
"brand_name": "Your Brand",
"chart_hash": "9c1f7a3e5b2d80461a3c5e7f9b2d0486",
"time_ms": 4210
}
Errors
Failures come back with success: false and an error string:
{
"success": false,
"error": "Missing: hour, minute"
}
| HTTP | Cause | Fix |
|---|---|---|
| 400 | Unknown report_type | Use an exact value from the reports list — hyphens, not underscores. |
| 400 | Missing required fields | The response names them; all birth fields are mandatory. |
| 401 | Invalid or missing API key | Check the X-Api-Key header. |
| 402 | Insufficient wallet balance | Top up, then retry. Nothing is charged on a failed call. |
| 403 | Report not enabled on your plan | Check what your plan unlocks in the dashboard. |
Notes
- Calls return quickly. The API responds as soon as it has queued the next batch and then keeps working in the background, so you are not holding a connection open while the PDF is written.
- Reports are billed from your wallet balance, not your API request credits.
- Branding comes from your account settings unless you override it per request.
- Timezone is an IANA timezone ID such as
Asia/KolkataorAmerica/New_York, taken from the birth place. - Requesting the same birth details and report type again returns the existing report rather than building a new one, as long as its link hasn't expired. You are not charged twice.
- Download links expire after 7 days.