# Creating Report Print Tasks

<div style="text-align: justify;">

A `ReportPrintTask` represents a single print job — a PDF queued for delivery to a physical printer. VeloxFactory does not communicate with printers directly. Instead, it creates the task record, optionally notifies a separate print service via WebSocket, and waits for the service to report back. This page covers how tasks are created, how the status lifecycle works, and how to handle retries.

[![report-print-task.index.png](https://docs.veloxfactory.kiwi-software.dev/uploads/images/gallery/2026-05/scaled-1680-/report-print-task-index.png)](https://docs.veloxfactory.kiwi-software.dev/uploads/images/gallery/2026-05/report-print-task-index.png)

---

<h3 id="three-ways" style="color: #203671; margin-top: 2.2em;">Three Ways to Create a Print Task</h3>

<h4 style="color: #203671; margin-top: 1.4em;">1. As Part of a Render Request</h4>

The most common path: set `createPrintTask: true` in the render request body, provide a `printerName`, and VeloxFactory renders the report and dispatches it to the printer in a single call. No second request needed.

```json
POST /api/v1/report-config/A5_KanBan/render

{
  "outputType": "base64",
  "parameters": { "P_ARTICLE_NUMBER": "4561287-154" },
  "data": [ { ... } ],
  "createHistoryRecord": true,
  "createPrintTask": true,
  "printerName": "WarehousePrinter01",
  "numberOfCopies": 1,
  "broadcastId": "Standard"
}
```

<h4 style="color: #203671; margin-top: 1.4em;">2. From a History Record</h4>

A task can be dispatched from any existing `ReportHistoryRecord` — without re-rendering the report. VeloxFactory uses the PDF stored in the history record and creates a new print task from it:

```
POST /api/v1/report-history-record/{id}/print
```

```json
{
  "printerName": "WarehousePrinter01",
  "numberOfCopies": 2
}
```

This is the standard reprint path. See [The concept of Report History Records](#) for details.

<h4 style="color: #203671; margin-top: 1.4em;">3. Standalone via the Print Task API</h4>

Print tasks can also be created directly — independently of any render or history record. The `POST /api/v1/report-print-task` endpoint accepts any PDF as a Base64 string, making it possible to use the VeloxFactory print infrastructure for documents that were not produced by VeloxFactory at all.

```json
POST /api/v1/report-print-task

{
  "fileName":       "delivery_note_5521.pdf",
  "fileBase64":     "JVBERi0xLjQ...",
  "printerName":    "WarehousePrinter01",
  "numberOfCopies": 1,
  "broadcastId":    "Standard"
}
```

`reportConfig` and `reportHistoryRecord` are both optional on this endpoint — the task is created without either relation if they are not provided.

---

<h3 id="data-model" style="color: #203671; margin-top: 2.2em;">The Data Model</h3>

<table style="width: 100%; border-collapse: collapse;">
  <thead>
    <tr style="border-top: 1px solid #e6e8ef; border-bottom: 1px solid #e6e8ef;">
      <th style="text-align: left; padding: 6px 10px; white-space: nowrap;">Field</th>
      <th style="text-align: left; padding: 6px 10px;">Description</th>
    </tr>
  </thead>
  <tbody>
    <tr style="border-bottom: 1px solid #e6e8ef;">
      <td style="padding: 6px 10px; white-space: nowrap;"><code>traceId</code></td>
      <td style="padding: 6px 10px;">Unique identifier. Shared with the linked history record when the task was created via a render request. For reprints, a derived trace ID is generated (original + short random suffix).</td>
    </tr>
    <tr style="border-bottom: 1px solid #e6e8ef;">
      <td style="padding: 6px 10px; white-space: nowrap;"><code>reportConfig</code></td>
      <td style="padding: 6px 10px;">The <code>ReportConfig</code> the printed PDF was generated from. Optional — not present for standalone tasks.</td>
    </tr>
    <tr style="border-bottom: 1px solid #e6e8ef;">
      <td style="padding: 6px 10px; white-space: nowrap;"><code>reportHistoryRecord</code></td>
      <td style="padding: 6px 10px;">The linked <code>ReportHistoryRecord</code>. Optional — not present for standalone tasks.</td>
    </tr>
    <tr style="border-bottom: 1px solid #e6e8ef;">
      <td style="padding: 6px 10px; white-space: nowrap;"><code>printerName</code></td>
      <td style="padding: 6px 10px;">The name of the target printer, as the print service expects it.</td>
    </tr>
    <tr style="border-bottom: 1px solid #e6e8ef;">
      <td style="padding: 6px 10px; white-space: nowrap;"><code>numberOfCopies</code></td>
      <td style="padding: 6px 10px;">Number of copies passed to the print service. VeloxFactory always renders once — the print service is responsible for duplication. Defaults to <code>1</code>.</td>
    </tr>
    <tr style="border-bottom: 1px solid #e6e8ef;">
      <td style="padding: 6px 10px; white-space: nowrap;"><code>broadcastId</code></td>
      <td style="padding: 6px 10px;">WebSocket channel ID. If set at creation time, VeloxFactory broadcasts a <code>ReportPrintTaskCreated</code> event via Laravel Reverb. Omit to use polling instead.</td>
    </tr>
    <tr style="border-bottom: 1px solid #e6e8ef;">
      <td style="padding: 6px 10px; white-space: nowrap;"><code>outputFileName</code></td>
      <td style="padding: 6px 10px;">The filename of the PDF queued for printing.</td>
    </tr>
    <tr style="border-bottom: 1px solid #e6e8ef;">
      <td style="padding: 6px 10px; white-space: nowrap;"><code>status</code></td>
      <td style="padding: 6px 10px;">Current state of the task. See below.</td>
    </tr>
    <tr>
      <td style="padding: 6px 10px; white-space: nowrap;"><code>errorMessage</code></td>
      <td style="padding: 6px 10px;">Failure detail reported by the print service. <code>null</code> unless status is <code>error</code>.</td>
    </tr>
  </tbody>
</table>

---

<h3 id="status-lifecycle" style="color: #203671; margin-top: 2.2em;">Status Lifecycle</h3>

Every print task starts as `pending`. The print service picks it up, executes the job, and reports the result back to VeloxFactory via the API:

<table style="width: 100%; border-collapse: collapse;">
  <thead>
    <tr style="border-top: 1px solid #e6e8ef; border-bottom: 1px solid #e6e8ef;">
      <th style="text-align: left; padding: 6px 10px; white-space: nowrap;">Status</th>
      <th style="text-align: left; padding: 6px 10px;">Set by</th>
      <th style="text-align: left; padding: 6px 10px;">Meaning</th>
    </tr>
  </thead>
  <tbody>
    <tr style="border-bottom: 1px solid #e6e8ef;">
      <td style="padding: 6px 10px;"><span style="color: #203671; font-weight: 600;">pending</span></td>
      <td style="padding: 6px 10px;">VeloxFactory</td>
      <td style="padding: 6px 10px;">Task created, waiting for the print service to pick it up.</td>
    </tr>
    <tr style="border-bottom: 1px solid #e6e8ef;">
      <td style="padding: 6px 10px;"><span style="color: #349b31; font-weight: 600;">printed</span></td>
      <td style="padding: 6px 10px;">Print service</td>
      <td style="padding: 6px 10px;">Print job executed and confirmed.</td>
    </tr>
    <tr style="border-bottom: 1px solid #e6e8ef;">
      <td style="padding: 6px 10px;"><span style="color: #c0392b; font-weight: 600;">error</span></td>
      <td style="padding: 6px 10px;">Print service</td>
      <td style="padding: 6px 10px;">Print job failed. <code>errorMessage</code> contains the failure detail.</td>
    </tr>
    <tr>
      <td style="padding: 6px 10px;"><span style="color: #525E5A; font-weight: 600;">unknown</span></td>
      <td style="padding: 6px 10px;">—</td>
      <td style="padding: 6px 10px;">Status could not be determined.</td>
    </tr>
  </tbody>
</table>

The print service reports back using the dedicated status endpoint:

```
PATCH /api/v1/report-print-task/{id}/set-status

{
  "status": "error",
  "errorMessage": "Printer offline"
}
```

<h4 style="color: #203671; margin-top: 1.4em;">Resetting to Pending</h4>

A task can be reset to `pending` using the set-printed shortcut endpoint — setting the status flag to `false`:

```
PATCH /api/v1/report-print-task/{id}/set-printed/false
```

This re-queues the task. If the task has a `broadcastId`, VeloxFactory re-broadcasts the `ReportPrintTaskCreated` event immediately — notifying the print service to pick the task up again without polling. This is the standard retry mechanism for failed or stalled print jobs.

---

<h3 id="websocket-vs-polling" style="color: #203671; margin-top: 2.2em;">WebSocket vs. Polling</h3>

How the print service learns about a new task depends on whether a `broadcastId` is set.

**With `broadcastId`** — VeloxFactory broadcasts a `ReportPrintTaskCreated` event via WebSocket (Laravel Reverb) the moment the task is created. The print service subscribes to the channel identified by `broadcastId` and reacts immediately. This is the recommended mode for real-time printing — the task reaches the printer within milliseconds of the render completing.

**Without `broadcastId`** — No broadcast is sent. The print service must poll `GET /api/v1/report-print-task?status=pending` at a regular interval and process any tasks it finds. This works fine for workflows where sub-second delivery is not required.

<div style="border-left: 4px solid #5fc75d; background: #f6fdf6; padding: 10px 16px; margin: 16px 0; border-radius: 0 4px 4px 0;">
ℹ️ <strong>WebSocket delivery requires Laravel Reverb to be running.</strong> If Reverb is down, task creation will fail with an error rather than falling back silently to polling. Use Supervisor to keep the Reverb process alive — the same Supervisor configuration that manages the Laravel queue worker should include a <code>php artisan reverb:start</code> program entry. See <a href="/books/veloxfactory/page/installing-veloxfactory">Installing VeloxFactory</a> for a reference configuration.
</div>

---

<h3 id="retention" style="color: #203671; margin-top: 2.2em;">Retention and Deletion</h3>

Print tasks are automatically purged after a configurable number of days, set via the `PURGE_PRINTTASKS_DAYS` environment variable (default: 30 days). Purging runs as a scheduled background job — no manual action required.

Individual tasks can also be deleted directly via the API at any time:

```
DELETE /api/v1/report-print-task/{id}
```

There are no deletion constraints on print tasks themselves — they can always be removed. However, deleting a print task is a prerequisite for deleting the linked `ReportHistoryRecord`, which in turn must be cleared before a `ReportConfig` can be deleted. Automatic purging handles this chain in the background once retention periods expire.

</div>