Skip to main content

Meet the API

VeloxFactory ships with a fully capable REST API, and it is not an afterthought. Every action you can perform in the frontend can also be performed via the API, because the frontend and the API share the same controller methods. There is no separate implementation, no feature gap, no second-class citizen.

This makes the API a genuine alternative to the UI, not just an integration bolt-on. Automate report rendering in your CI pipeline, trigger prints from your ERP, manage report configurations programmatically, have VeloxFactory run the whole thing on a schedule, all with the same logic that powers the frontend you already know.

ℹ️ For the full endpoint reference including all parameters and response schemas, explore the live demo API documentation at demo.veloxfactory.dev.

Login: demo@veloxfactory.dev  ·  Password: demo


Authentication

The API uses token-based authentication via Laravel Sanctum. Every request must include a Bearer token in the Authorization header.

Authorization: Bearer your-api-token
⚠️ Every API request requires global:use-api. The permission is checked on each call, not only when a token is issued. A token whose user does not hold it is answered with 403, even if the token itself is valid and the user has the resource permissions.

Tokens are issued and revoked per user in the user management section of the frontend. A request authenticated by a token cannot create or revoke tokens, so a leaked token cannot renew itself and revoking it actually locks it out. A revoked token is rejected immediately, there is no grace period.

{
  "success": false,
  "errors": ["This API token has been revoked."],
  "status": 401
}

The audit trail records which token was used for every create and update operation across all models, so every API action is fully traceable.

Authentication Errors

Status Message When
401 This user account is disabled. The account behind the token was deactivated
401 This API token has been revoked. The token was revoked, or every token of the user was revoked by a password change or a deactivation
401 Token expired The token is older than SANCTUM_EXPIRATION
403 This user is not permitted to use the API. The user is missing global:use-api
403 API tokens can only be managed from the web interface. A token tried to create or revoke a token

Base URL

All API v1 endpoints are prefixed with:

/api/v1/

Referencing Records

Wherever a request points at another record, it accepts either the numeric ID or the unique name of that record. These two are the same call:

POST /api/v1/report-config/12/render
POST /api/v1/report-config/Shift Report/render

The same holds inside request bodies, for report contexts, connection configs, mailers, mail templates and schedules alike, so a payload stays readable without a lookup table of IDs. A Report History Record is addressed by its ID or by its trace id, which is what makes a trace id worth carrying through your own systems.

ℹ️ A value of digits only is always read as an ID. That is why a name cannot consist of digits only. VeloxFactory refuses such a name when a record is created or renamed, so 4711 is never ambiguous.

Response Structure

All API responses follow a consistent envelope format.

Success, list endpoint:

{
  "success": true,
  "count": 25,
  "data": [ { ... }, { ... } ],
  "links": {
    "first": "https://your-instance/api/v1/report-print-task?status=pending&page=1",
    "last": "https://your-instance/api/v1/report-print-task?status=pending&page=3",
    "prev": null,
    "next": "https://your-instance/api/v1/report-print-task?status=pending&page=2"
  },
  "meta": {
    "pagination": {
      "currentPage": 1,
      "lastPage": 3,
      "perPage": 25,
      "total": 61,
      "from": 1,
      "to": 25,
      "hasMorePages": true,
      "path": "https://your-instance/api/v1/report-print-task"
    }
  },
  "status": 200
}

Success, single record:

{
  "success": true,
  "count": 1,
  "data": { ... },
  "links": { "first": null, "last": null, "prev": null, "next": null },
  "meta": {
    "pagination": {
      "currentPage": 1,
      "lastPage": 1,
      "perPage": 1,
      "total": 1,
      "from": 1,
      "to": 1,
      "hasMorePages": false,
      "path": "https://your-instance/api/v1/report-print-task/256"
    }
  },
  "status": 200
}

Error:

{
  "success": false,
  "errors": ["Descriptive error message"],
  "meta": {},
  "status": 404
}

Every success response that carries data has the same shape, whether it returns a list, a single record, a freshly created record or a render result. A client parses one envelope for every endpoint.

  • count is the number of records in data: the records on the current page for a list, 1 for a single record.
  • links point to the first, last, previous and next page. A link that does not exist is null. Responses that are not paginated have all four links null.
  • meta.pagination describes the page, see Pagination. A response that is not paginated reports exactly one page.
  • meta carries further contextual information next to pagination, such as the traceId of a render run or the mailing result.

Error responses have no links and no pagination block.


Pagination

All list endpoints (GET /user, GET /report-config, GET /report-print-task and every other GET on a resource without an id) return their records page by page. Two query parameters control the page:

Parameter Type Default Description
page integer 1 Page to return, starting at 1.
perPage integer 25 Records per page, 1 to 100.

The values of the pagination block:

Field Meaning
currentPage The page in this response.
lastPage Number of the last page, at least 1.
perPage Page size used for this response.
total Number of all records matching the request, across all pages.
from / to Position of the first and last record of this page within total, null on an empty page.
hasMorePages true as long as a next page exists.
path URL of the endpoint without query string.

Filters such as status, type or isActive apply before the records are split into pages, so total counts the filtered result. The links in links carry all query parameters of the request, a client follows links.next until it is null and keeps its filters on every page.

A page behind the last one returns 200 with an empty data array. A page below 1, a perPage above 100 or a non-numeric value returns 422.

To read every record, request perPage=100 and follow links.next. Every page is a request of its own and counts against the rate limit.

The two placeholder catalogs (GET /mail-template/placeholders, GET /scheduled-job/placeholders) are not paginated and always return one page.

The page size default and maximum are set with API_PER_PAGE_DEFAULT and API_PER_PAGE_MAX, see Configuration and Data Models.

ℹ️ limit is a deprecated alias of perPage and will be removed in a future version. perPage takes precedence when both are sent, and limit=0 returns the maximum page size. There is no request that returns all records at once.

Query Parameters

Most GET endpoints and the render endpoint share a common set of query parameters that control what is included in the response. They are additive, combine them freely.

Parameter Type Default Description
page, perPage integer 1, 25 Page and page size on list endpoints, see Pagination.
withRelations boolean false Include related models (e.g. parameters, fields, resources on a ReportConfig).
recursiveRelations boolean false Include nested relations within relations.
withMedia boolean false Include Base64-encoded file content, previews, and thumbnails.
withAudit boolean false Include the audit segment on each record (timestamps, users, token, method).

Example, retrieve a single report config with all relations, media, and audit data:

GET /api/v1/report-config/1?withRelations=true&withMedia=true&withAudit=true

Audit Segment

When withAudit=true is set, every record in the response carries an audit block:

"audit": {
  "createdAt": "2026-05-08 11:26:30",
  "createdByUser": 2,
  "createdByToken": null,
  "creationMethod": "Frontend",
  "updatedAt": "2026-05-08 13:31:35",
  "updatedByUser": 1,
  "updatedByToken": "Postman",
  "updateMethod": "API"
}

creationMethod and updateMethod are derived automatically, "API" when a token was used, "Frontend" when the action came through the UI. A run of a scheduled job fills these exactly like a direct call does, with the owner of the schedule and the token it runs with.


Render-Specific Request Body

The render endpoint (POST /api/v1/report-config/{id}/render) accepts the following fields in the request body (JSON).

Field Type Required Description
outputTypestring✅How to return the PDF: base64, url, preview, or none
createHistoryRecordboolean✅Whether to persist a ReportHistoryRecord for this render
createPrintTaskboolean✅Whether to create a ReportPrintTask after rendering
printerNamestringif createPrintTaskName of the target printer
useExampleValuesbooleanUse stored example values instead of supplying parameters manually
parametersobjectKey-value map of parameter names to values
resourceOverridesobjectPer-render override for P_RESOURCE_* image parameters, keyed by parameter name. A path has to point at a readable file inside the resources folder, a URL has to be https://, or the image is supplied as a Base64 upload. See Rendering with our powerful API for the full reference.
dataarrayArray of data rows, for reports without a live DB connection
numberOfCopiesintegerNumber of print copies (default: 1)
broadcastIdstringWebSocket channel ID, triggers real-time status updates for the print task
traceIdstringCustom trace ID; auto-generated as UUID if omitted. Unique across all history records
laconicResponsebooleanStrip the response to just the PDF output (see below)
mailingobjectSend the rendering by mail once it succeeded: mailer, mail template, recipients, attachments and sync or queued dispatch. See Report Mailing for the full reference.
⚠️ Output type none requires createPrintTask: true. Rendering without any output and without a printer to send it to is rejected, and a mailing segment does not take the place of the print task. preview and mailing are refused together as well, a preview render deletes its own file immediately and has nothing to attach.

Laconic Responses

By default, a render response is fully populated, it includes the echoed input, the PDF output, the linked ReportConfig, the created ReportHistoryRecord, and the ReportPrintTask and ReportMailTask if applicable. In high-frequency or bandwidth-sensitive scenarios, add laconicResponse=true to strip everything down to just the PDF output.

The Same Body on a Schedule

This body is also what a render job of the Job Scheduler stores. A request you have tested here can be dropped into the payload of a schedule unchanged, minus traceId, which every run generates for itself. See Render Jobs.


Rate Limiting

The API enforces a configurable rate limit per token. The default is 10 requests per minute. When the limit is exceeded:

{
  "success": false,
  "message": "Too many requests! The current rate limiting is 10 requests per minute.",
  "status": 429
}

The limit is adjusted via the API_RATE_LIMIT_PER_MINUTE environment variable, see Configuration and Data Models.


Endpoints Overview

Resource Available operations
User List, show, create, update, change password, enable/disable, create/revoke tokens (web interface only)
ReportContext List, show, create, update, delete
ReportConnectionConfig List, show, create, update, delete, test connection
CommonReportResource List, show, create, update, delete
ReportConfig List, show, create, update, delete, update resources / parameters / fields, generate previews, render
ReportResource Link / unlink CommonReportResource
ReportHistoryRecord List, show, create, update, delete, print, mail
ReportPrintTask List, show, create, update, delete, set printed, set status
ReportMailTask List, show, create, delete, repeat
Printer List, show, create, update, delete
Mailer List, show, create, update, delete, test configuration, send test mail
MailTemplate List, show, create, update, delete, placeholder catalog, preview
ScheduledJob List, show, create, update, delete, run now, cron preview, placeholder catalog
ScheduledJobRun List, show, delete

A Practical Example: The Full Render Response

A render call returns a ReportRendering object. By default it is fully populated, you see the input you sent, the PDF output, and the linked records that were created.

{
  "success": true,
  "count": 1,
  "data": {
    "model": "ReportRendering",
    "traceId": "a3f9c1d2-4e87-4b2a-9f1c-d3e8b7a20f61",
    "input": {
      "parameters": {
        "P_ARTICLE_NUMBER": "4561287-154"
      },
      "data": null
    },
    "output": {
      "reportPdfFileName": "a3f9c1d2-4e87-4b2a-9f1c-d3e8b7a20f61.pdf",
      "reportPdfBase64": "JVBERi0xLjQ...",
      "reportUrl": null
    },
    "reportConfig": { "..." },
    "reportHistoryRecord": { "..." },
    "reportPrintTask": null
  },
  "links": { "first": null, "last": null, "prev": null, "next": null },
  "meta": {
    "traceId": "a3f9c1d2-4e87-4b2a-9f1c-d3e8b7a20f61",
    "pagination": {
      "currentPage": 1,
      "lastPage": 1,
      "perPage": 1,
      "total": 1,
      "from": 1,
      "to": 1,
      "hasMorePages": false,
      "path": "https://your-instance/api/v1/report-config/12/render"
    }
  },
  "status": 200
}

Add laconicResponse=true and the response collapses to just output, no echoed input, no embedded related records. Ideal for automated pipelines that only need the PDF.