Meet the API
JasperWho 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 — all with the same logic that powers the frontend you already know.
Login: demo@jasper.who · 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
Tokens are created and managed per user — either from the user management section in the frontend, or via the API itself (POST /api/v1/user/{id}/create-token). Each token can be revoked at any time. 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.
Base URL
All API v1 endpoints are prefixed with:
/api/v1/
Response Structure
All API responses follow a consistent envelope format.
Success:
{
"success": true,
"count": 1,
"data": { ... },
"meta": [],
"status": 200
}
Error:
{
"success": false,
"errors": ["Descriptive error message"],
"meta": {},
"status": 404
}
The count field reflects the number of records in data — 1 for single-record responses, the actual number of returned records for collections. The meta field carries contextual information such as the traceId of a render run.
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 |
|---|---|---|---|
limit |
integer | 25 |
Maximum records to return. Set to 0 for all. |
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.
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 |
|---|---|---|---|
outputType | string | ✅ | How to return the PDF: base64, url, preview, or none |
createHistoryRecord | boolean | ✅ | Whether to persist a ReportHistoryRecord for this render |
createPrintTask | boolean | ✅ | Whether to create a ReportPrintTask after rendering |
printerName | string | if createPrintTask | Name of the target printer |
useExampleValues | boolean | Use stored example values instead of supplying parameters manually | |
parameters | object | Key-value map of parameter names to values | |
data | array | Array of data rows — for reports without a live DB connection | |
numberOfCopies | integer | Number of print copies (default: 1) | |
broadcastId | string | WebSocket channel ID — triggers real-time status updates for the print task | |
traceId | string | Custom trace ID; auto-generated as UUID if omitted | |
laconicResponse | boolean | Strip the response to just the PDF output (see below) |
none requires createPrintTask: true. Rendering without any output and without a print task is rejected.
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 if applicable. In high-frequency or bandwidth-sensitive scenarios, add laconicResponse=true to strip everything down to just the PDF output.
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 |
| 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 |
| ReportPrintTask | List, show, create, update, delete, set printed, set status |
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
},
"meta": {
"traceId": "a3f9c1d2-4e87-4b2a-9f1c-d3e8b7a20f61"
},
"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.