GRANSKA

Download a job's PDF

GEThttps://api.granska.cloud/v1/jobs/:jobId/result.pdf

Downloads a completed job's report or generated document as the same PDF the app exports.

Bearer tokenSpends no quota

What you get

A completed analysis job answers with the analysis report; a completed action job answers with the generated action document. It is the same document a user gets from the download button in the app: the same layout, the same fonts and the same wording, built from the same result and from your workspace's configuration — the review profile names that head each angle of a review package, and the section layout of the action. Only the file metadata, such as the creation time, differs between two downloads.

The response is Content-Type: application/pdf with a Content-Disposition filename made only of letters, digits, -, _ and ., so it is safe to write to disk as it stands. Save the body as binary; it is not JSON.

This is our document about the file you sent, not that file. The PDF you uploaded is never returned.

What it does not do

It renders, it does not store. The PDF is built from the job's result when you ask for it and streamed back. It is not written to a database, a bucket or a cache, and the response carries Cache-Control: no-store.

It does not keep the job alive. Downloading reads the job exactly as reading a job does and changes nothing on it, so it does not reset the retention clock. The retention sweep deletes the job and its stored result once it has not changed in the last fifteen minutes, whether or not you have downloaded, and from then on this route answers 404 like every other route that names the job — there is nothing left to render from. If you need the document later, save the file.

It costs no run. Rendering is not an analysis, and this route draws nothing from your quota. You can download the same job as often as you like until it is swept.

Request
curl https://api.granska.cloud/v1/jobs/job_7d41c9/result.pdf \
  -H "Authorization: Bearer $TOKEN" \
  --fail --output report.pdf
Response
HTTP/1.1 200 OK
Content-Type: application/pdf
Content-Disposition: attachment; filename="analysis-job_7d41c9.pdf"
Cache-Control: no-store

%PDF-1.3 … (the report, as binary PDF)

Add ?includeTrace=true and a completed analysis's PDF ends with its legal trace: for each review in the run, the legal sources its findings cite and the sources its reviewers were supplied, the citations that do not match the sources supplied to that review, and the sources the strengths cite. It is the same appendix, in the same place after the report, that the app adds to its export when the trace is switched on, and it is labelled in the analysis's own language.

curl "https://api.granska.cloud/v1/jobs/job_7d41c9/result.pdf?includeTrace=true" -H "Authorization: Bearer $TOKEN" --fail --output report-with-trace.pdf

Only the literal true turns it on. Leave the parameter out, or send false, and you get the document described above, unchanged, even when the run has a trace. Any other value — 1, TRUE, an empty value — or the parameter sent twice answers 400 BAD_REQUEST. The check comes after the job is found and shown to be yours, so a 404 or 403 comes first.

Traces exist for analyses only. An action job asked for its trace answers 409 CONFLICT; ask again without includeTrace, or with false, for its document.

No trace means 409, never a PDF without one. An analysis whose run has no valid trace — one that finished before traces existed, or whose stored trace does not pass validation — answers 409 CONFLICT instead of a document. A file without the appendix would look like a trace that cited nothing. Reading the job with includeTrace=true then reports its result.analysisTrace as null.

Supplied means given to the reviewer, not relied upon. A source listed as supplied was loaded into what that reviewer was shown. It is not a statement that the assessment rested on it, and the appendix keeps it apart from the sources the report cites.

Nothing else changes: the trace is read from the job's own stored result, the document is rendered on request and not stored, the response carries Cache-Control: no-store, the download draws nothing from your quota and does not keep the job alive, and the retention sweep removes the trace with the rest of the job.

Request

ParameterDescription
jobId
string·path·required
The id POST /v1/analyze or POST /v1/action returned, once GET /v1/jobs/:jobId reports it COMPLETED.
includeTrace
"true" | "false"·query
Set to "true" to append the analysis's legal trace: the same appendix, after the report, that the app's export adds when the trace is switched on. Omitted or "false", the PDF is unchanged. An action job, or an analysis whose run has no valid trace, answers 409. Any other value, or the parameter sent twice, answers 400.

Errors

Every refusal is the ordinary JSON error envelope, never a partial PDF — check the status before saving the body. With curl --fail, as in the example, a refusal leaves no file behind.

A job still QUEUED or IN_PROGRESS, and a job that FAILED, has no document and answers 409 CONFLICT. Poll the job until it is COMPLETED. With includeTrace=true, an action job and an analysis without a valid trace also answer 409, and an includeTrace other than true or false, or sent twice, answers 400. A job your credential did not start answers 403: another organisation's job, one another API client of yours started, or one a person started in the web application or the API tester. So does an action job whose action your workspace is no longer licensed for, because the action's layout is what the document is built from. A job that never existed, or has already been swept, answers 404.

ErrorWhen
400
BAD_REQUEST
includeTrace is something other than "true" or "false", or is sent more than once. Checked after the job is found and shown to be yours, so a 404 or 403 comes first. Not probed: it needs a job the probing credential started.
401
UNAUTHORIZED
The Authorization header is missing, is not a readable bearer token, or names no tenant.
401
TOKEN_EXPIRED
The access token was issued by this gateway and has since expired. Not probed: it needs a token older than its own lifetime.
403
FORBIDDEN
The job exists but your credential did not start it (another organisation's job, one another API client of yours started, or one a person started in the web application or the API tester), or it is an action job whose action is no longer licensed for this tenant, so its layout cannot be resolved. Not probed: it needs a job started by a second credential.
404
NOT_FOUND
No job with that id, or the retention sweep has already removed it. Downloading the PDF does not delete the job and does not keep it alive; `sweepStaleData` removes it once it has been untouched for 15 minutes, and nothing is kept to render from after that.
409
CONFLICT
The job has no document to render: it is still QUEUED or IN_PROGRESS, or it FAILED. Poll GET /v1/jobs/:jobId until COMPLETED. Also when includeTrace=true names an action job, since legal traces exist for analyses only, or an analysis whose run has no valid legal trace, rather than a PDF without one. Not probed: it needs a job that is mid-flight or failed, or one the probing credential started.
500
INTERNAL_ERROR
An unexpected server-side failure. Not probable from outside — reaching it means something is wrong.