# Printing a report via the API?

**URL:** <https://speciforum.org/t/printing-a-report-via-the-api/4025>\
**Category:** Get Help\
**Created:** [August 13, 2026, 9:51pm UTC](https://speciforum.org/t/printing-a-report-via-the-api/4025 "2026-08-13T21:51:41Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![nfshoobs](https://yyz1.discourse-cdn.com/flex029/user_avatar/speciforum.org/nfshoobs/32/3979_2.png) [@nfshoobs](https://speciforum.org/u/nfshoobs)\
**Post date:** [August 13, 2026, 9:51pm UTC](https://speciforum.org/t/printing-a-report-via-the-api/4025/1 "2026-08-13T21:51:41Z")

</div>

Is there presently a way to run a report query (and thus generate a label or report) for a record (or set of records) via the API?

I imagine not, because the report runner doesn’t have a unique URL response and the reports do not persist on the server after the report runner is closed, right?

Could potentially be grouped with my previous post here, under the broader theme of “improvements to report runner” [Feature Request: Allow customization of filenames in Report Runner](https://speciforum.org/t/feature-request-allow-customization-of-filenames-in-report-runner/2998)

---

<div class="post-metadata">

**Author:** ![Grant](https://yyz1.discourse-cdn.com/flex029/user_avatar/speciforum.org/grant/32/4255_2.png) [@Grant](https://speciforum.org/u/Grant)\
**Post date:** [August 17, 2026, 7:58pm UTC](https://speciforum.org/t/printing-a-report-via-the-api/4025/2 "2026-08-17T19:58:49Z")

</div>

Hi @nfshoobs,

Technically there is an API for it, via `POST /report_runner/run/`, since Specify just POSTs a form to this endpoint with `report` (JRXML), `query` (JSON, incl. `recordSetId` for sets, or an id-filter for single records), and `parameters` (as a JSON object). The response _is_ the PDF itself, but it was designed to always be triggered by Specify alone and not another source.

You’re right that there is no persistence since the PDF is rendered on the fly each time, so it isn’t really stored anywhere long-term. There’s also not a unique URL really, since the endpoint’s body is the PDF.

It’s really not designed to be used since there’s no API auth on this endpoint. To use it, you’d need to replicate the whole stack (session, auth, CSRF token) and send the expected request.

---

<div class="post-metadata">

**Author:** ![jason\_m](https://avatars.discourse-cdn.com/v4/letter/j/8e8cbc/32.png) [@jason\_m](https://speciforum.org/u/jason_m)\
**Post date:** [August 17, 2026, 8:38pm UTC](https://speciforum.org/t/printing-a-report-via-the-api/4025/3 "2026-08-17T20:38:23Z")

</div>

If anyone is planning on using Specify’s endpoint for this (`/report_runner/run/`), here’s some additional information that should be helpful.

> ⚠ The `/report_runner/run/` endpoint in Specify 7 is undocumented and largely considered “internal” by the Specify team.  
> You are free to use it in your own projects, but it might be subject to change in the future.  
> Use it at your own risk

The following is the location within the Specify7 code where the request is handled.  
If you’re able to read and parse Python code, this is the best place to learn how it works:

> <https://github.com/specify/specify7/blob/383e28cf914124c0a12b8b05c364b331a1311385/specifyweb/backend/report_runner/views.py#L39-L66>

If you plan on using the Report Runner directly, below is the relevant code that handles the request (written in Java)

> <https://github.com/specify/report-runner-service/blob/b69ee43adcf3fc1cc449e2a3194a0a66407d58ab/src/main/java/edu/ku/brc/specify/reports/ReportServlet.java#L28-L61>

The Report Runner is completely stateless, meaning it has no persistence and no concept of which Queries map to which Reports. The physical report and associated results which act as the report’s “data source” have to be handed to the Report Runner for each request.

For the Specify 7 `/report_runner/run/` POST endpoint, the request body should be in [x-www-form-urlencoded](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Methods/POST#url-encoded_form_submission) format and have the three key+value pairs aforementioned by Grant:

- query
  - A serialized/stringified JSON representation of the Query that will be run by Specify to retrieve the result to be passed to the Report Runner

- report
  - A serialized/stringified XML representation of the report (i.e., the JRXML of the report you want to run, as a string)

- parameters
  - The report parameters (if any) in a serialized JSON format
  - A report parameter is a non-QueryBuilder field value mapped to a name that is entered by the user before a report is ran
  - These would be on your reports with something like `parameter[isForPrompting="true"]`
  - Most reports probably won’t have parameters, but this key+value pair is still required

The Specify 7 endpoint does make sure the executing user has the correct permissions to execute reports and read the tables present in the serialized Query.

The Specify 7 backend can respond in three different ways:

- With a 200 status code, a `text/plain` Content Type, and the text `The report query returned no results.` if the serialized Query did not return any results
- With a 200 status code, an `application/pdf` Content Type, and the resulting PDF as conent
- With a 500 status code and an exception message if the Report Runner was not able to correctly process the report

---

<div class="post-metadata">

**Author:** ![system](https://canada1.discourse-cdn.com/flex029/uploads/specifysoftware/original/2X/1/18a843c97bc32b40e8ad0e035755bc88ffaacaf7.svg) [@system](https://speciforum.org/u/system)\
**Post date:** [August 24, 2026, 8:38pm UTC](https://speciforum.org/t/printing-a-report-via-the-api/4025/4 "2026-08-24T20:38:40Z")

</div>

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.
