Skip to content

Reports

Rendered report artifacts (HTML or PDF). Report generation is asynchronous — the API enqueues a job, returns immediately with a pending status, and the client polls until the artifact is ready.

Create — POST /v1/reports

Required scope: reports:write

Request

{
    "chart_id": "019e32b5-...",
    "kind": "talent_lens",
    "format": "pdf",
    "locale": "en",
    "tone": "corporate"
}
Field Type Required Notes
chart_id UUIDv7 yes Must belong to the caller's tenant.
kind enum no, default "talent_lens" Report template family: talent_lens or personal_reader.
format enum no, default "html" Output format: html or pdf.
locale enum no, default "en" Statement language: en, hi, or ru.
tone enum no, default "corporate" Voice: corporate, coach, vedic_traditional, or plain.
Idempotency-Key (header) string no Prevents duplicate jobs on retry.

Response — 202 Accepted

{
    "id": "019e32cb-2079-7862-a51a-276717f48920",
    "chart_id": "019e32b5-...",
    "kind": "talent_lens",
    "format": "pdf",
    "status": "pending",
    "created_at": "2026-05-16T22:01:00Z",
    "updated_at": "2026-05-16T22:01:00Z",
    "artifact_url": null,
    "artifact_key": null,
    "error": null
}

Save id, then poll.

Fetch — GET /v1/reports/{id}

Required scope: reports:read

Same shape as create. The fields you care about:

Field Notes
status One of pending, running, ready, failed.
artifact_url Set only when status == "ready". Short-lived signed URL.
artifact_key The object-storage key — useful if you have your own S3 read access.
error Set only when status == "failed". Free-text reason.

artifact_url is signed by the storage backend (S3 / MinIO) and typically expires within 24 hours. Re-fetch the report to mint a new URL.

Polling

A typical loop:

until [ "$(curl -sS $URL/v1/reports/$ID -H "$AUTH" | jq -r .status)" = "ready" ]; do
    sleep 2
done

In practice reports complete within a few seconds. If polling exceeds 60 s with status: pending, the worker is likely backlogged — open a support ticket with the request_id.

Webhooks

Not yet supported. Subscribe to the changelog for the rollout.

Idempotency

Pass Idempotency-Key: <client-generated-uuid> on the create request. The first call enqueues the job and caches the response under that key; subsequent calls with the same key return the cached record (including the eventual ready status) without re-enqueuing. The key lifetime is 24 hours.

This is the recommended pattern for any client retry loop — exponential backoff + idempotency key.

Failure modes

error Meaning Action
chart_not_found Chart deleted between enqueue and processing. None — surface to the user.
template_render_failed WeasyPrint could not produce a PDF. Typically a bad asset. Retry.
storage_upload_failed S3 / MinIO returned an error. Retry.
worker_timeout Job exceeded the per-message timeout (default 60 s). Retry, or open a ticket.

Worker failures are retried automatically (exponential backoff, up to three attempts). The final failure surfaces here.