POST · REPORTS

Generate Report

Endpoint 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

MethodHow
Header (recommended)X-Api-Key: YOUR_KEY
Body"api_key": "YOUR_KEY"

Request body

Fields for single-chart reports (everything except kundli-matching):

FieldTypeRequiredDescription
report_typestringYesWhich report to generate — see available reports.
person_namestringYesName printed on the cover and used throughout the text.
genderstringNomale or female. Defaults to male.
yearintegerYesBirth year, e.g. 1990.
monthintegerYesBirth month, 112.
dayintegerYesBirth day of month.
hourintegerYesBirth hour, 24-hour clock.
minuteintegerYesBirth minute.
secondintegerNoBirth second. Defaults to 0.
latitudefloatYesBirth latitude, e.g. 28.6139.
longitudefloatYesBirth longitude, e.g. 77.2090.
timezonestringYesIANA timezone ID of the birth place, e.g. Asia/Kolkata.
ayanamsastringNoDefaults to lahiri.
brand_namestringNoOverrides your saved brand for this report only.
brand_taglinestringNoTagline under the brand name on the cover.
brand_urlstringNoWebsite shown on the PDF.
brand_logo_urlstringNoPublic 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.

FieldTypeRequiredDescription
report_typestringYesSet to kundli-matching.
person1objectYesFirst person — name, gender and birth details.
person2objectYesSecond person, same shape.
chart_stylestringNonorth_indian (default) or south_indian.
languagestringNoISO 639-1 code. Defaults to en.
ayanamsastringNoDefaults to lahiri. Applies to both charts.

The person object

Both person1 and person2 take the same fields:

FieldTypeRequiredDescription
namestringNoUsed throughout the report text. Falls back to Bride / Groom if omitted.
genderstringYesmale or female — decides which chart is treated as bride and which as groom.
yearintegerYesBirth year.
monthintegerYesBirth month, 112.
dayintegerYesBirth day of month.
hourintegerYesBirth hour, 24-hour clock.
minuteintegerYesBirth minute.
secondintegerNoDefaults to 0.
latitudefloatYesBirth latitude.
longitudefloatYesBirth longitude.
timezonestringYesIANA 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 the download_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:

HTTPstatusMeaning
200readyPDF is built and downloadable.
202preparingStill building — keep calling the generate endpoint.
400invalidToken is missing or malformed.
404not_foundNo report exists for that token.
410expiredLink is older than its expiry window — generate a fresh report.
500failedGeneration 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

FieldTypeDescription
successbooleantrue when the call was accepted.
statusstringprocessing while sections remain, ready once the PDF exists.
download_urlstringHosted URL of the PDF. Stable from the first call onward.
tokenstring64-character identifier for this report, also embedded in the download URL.
messagestringHuman-readable progress note, safe to show your user while they wait.
progressobjectPresent while processing: done, total and percent — ideal for a progress bar.
person_namestringEchoed back from the request.
chart_hashstringFingerprint of the birth chart, used internally to detect repeat requests.
time_msintegerHow 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"
}
HTTPCauseFix
400Unknown report_typeUse an exact value from the reports list — hyphens, not underscores.
400Missing required fieldsThe response names them; all birth fields are mandatory.
401Invalid or missing API keyCheck the X-Api-Key header.
402Insufficient wallet balanceTop up, then retry. Nothing is charged on a failed call.
403Report not enabled on your planCheck 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/Kolkata or America/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.

See also