Scrapes QSE, global indices, GCC markets, commodities & news. Generates a ready-to-share PDF.
Report generation is asynchronous — it scrapes 15+ data sources while running in the background.
Start a job with POST /api/report/generate, then poll GET /api/report/status/:jobId
until status is "done", then download the PDF.
Starts a background report generation job. Returns a jobId immediately — use it to poll status.
| Header | Type | Description | |
|---|---|---|---|
| Content-Type | string | required | Must be application/json |
| X-Pass-Key | string | optional | Required when PASS_KEY is set in server .env |
| Field | Type | Description | |
|---|---|---|---|
| reportDate | string | optional | Override the date label in the report header (e.g. "2025-01-15"). Defaults to today. |
| openaiApiKey | string | optional | Override the OpenAI key. Falls back to OPENAI_API_KEY in server .env. |
curl -X POST http://localhost:3000/api/report/generate \
-H "Content-Type: application/json" \
-H "X-Pass-Key: your-pass-key" \
-d '{}'
{
"success": true,
"jobId": "a1b2c3d4-e5f6-...",
"message": "Report generation started. Poll /api/report/status/a1b2c3d4-e5f6-... for progress.",
"totalSources": 15
}
Returns current job progress. Poll every 3–5 seconds until status is "done" or "error".
When done, the response includes a downloadUrl.
curl http://localhost:3000/api/report/status/a1b2c3d4-e5f6-... \ -H "X-Pass-Key: your-pass-key"
{
"success": true,
"jobId": "a1b2c3d4-e5f6-...",
"status": "running",
"progress": "Fetching QSE data…",
"step": 4,
"total": 15,
"startedAt": "2025-01-15T05:30:00.000Z",
"doneAt": null,
"error": null,
"downloadUrl": null,
"dataUrl": null
}
{
"success": true,
"jobId": "a1b2c3d4-e5f6-...",
"status": "done",
"progress": "Complete",
"step": 15,
"total": 15,
"startedAt": "2025-01-15T05:30:00.000Z",
"doneAt": "2025-01-15T05:33:42.000Z",
"error": null,
"downloadUrl": "/api/report/download/a1b2c3d4-e5f6-...",
"dataUrl": "/api/report/data/a1b2c3d4-e5f6-..."
}
Streams the generated PDF as a file download. Only available after status is "done".
Jobs are kept in memory — the server keeps the last 10 reports.
curl -O -J \ -H "X-Pass-Key: your-pass-key" \ http://localhost:3000/api/report/download/a1b2c3d4-e5f6-...
Content-Type: application/pdf Content-Disposition: attachment; filename="morning-market-note-qatar-2025-01-15.pdf" <binary PDF data>
Returns the raw collected market data as JSON. Useful for debugging, building custom renderers, or piping data to other systems.
curl http://localhost:3000/api/report/data/a1b2c3d4-e5f6-... \ -H "X-Pass-Key: your-pass-key"
{
"success": true,
"data": {
"report_date": "2025-01-15",
"qse": { ... },
"global_indices": [ ... ],
"gcc_markets": [ ... ],
"commodities": { ... },
"news": [ ... ]
}
}
#!/usr/bin/env bash
BASE="http://localhost:3000"
PASS_KEY="your-pass-key"
# 1. Start the job
JOB_ID=$(curl -s -X POST "$BASE/api/report/generate" \
-H "Content-Type: application/json" \
-H "X-Pass-Key: $PASS_KEY" \
-d '{}' | jq -r '.jobId')
echo "Job started: $JOB_ID"
# 2. Poll until done
while true; do
RESP=$(curl -s "$BASE/api/report/status/$JOB_ID" \
-H "X-Pass-Key: $PASS_KEY")
STATUS=$(echo "$RESP" | jq -r '.status')
PROGRESS=$(echo "$RESP" | jq -r '.progress')
STEP=$(echo "$RESP" | jq -r '.step')
TOTAL=$(echo "$RESP" | jq -r '.total')
echo "[$STEP/$TOTAL] $PROGRESS"
if [ "$STATUS" = "done" ]; then
echo "✓ Report ready"
break
elif [ "$STATUS" = "error" ]; then
echo "✗ Error: $(echo "$RESP" | jq -r '.error')"
exit 1
fi
sleep 4
done
# 3. Download the PDF
curl -O -J \
-H "X-Pass-Key: $PASS_KEY" \
"$BASE/api/report/download/$JOB_ID"
echo "✓ PDF downloaded"
OPENAI_API_KEY in .env so you don't need to pass it per-request. ·
Use /api/report/data/:jobId to get raw JSON if you want to build your own report renderer.