Reports
Access analysis reports generated by the ShieldCI Laravel package. The list and detail endpoints use different shapes: the list returns summary objects (no per-analyzer results), and the detail endpoint returns the full report including every analyzer's results and issues.
All endpoints require a valid Sanctum token. See Authentication for ability details.
Report IDs are UUIDs
The {report} URL parameter is always the report's UUID (data[].uuid in list responses, data.uuid in the detail response), not the integer id.
List Reports
GET/api/v1/projects/{project}/reportsRequires ability: read
Returns a paginated list of reports for a project, ordered by analysis date descending.
Request
| Header | Value | Required |
|---|---|---|
Authorization | Bearer shieldci_{token} | Yes |
Accept | application/json | Recommended |
| Parameter | Type | Description |
|---|---|---|
project | UUID string | Project UUID (from data[].id in List Projects) |
curl "https://shieldci.com/api/v1/projects/550e8400-e29b-41d4-a716-446655440000/reports?page=1" \
-H "Authorization: Bearer shieldci_{token}" \
-H "Accept: application/json"Response
{
"data": [
{
"id": 42,
"uuid": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
"score": 87,
"total": 100,
"passed": 87,
"failed": 8,
"warnings": 3,
"skipped": 2,
"errors": 0,
"total_issues": 11,
"issues_by_severity": {
"critical": 0,
"high": 1,
"medium": 4,
"low": 6,
"info": 0
},
"laravel_version": "12",
"package_version": "1.2.0",
"total_execution_time": 14.8,
"triggered_by": "api",
"analyzed_at": "2026-05-12T09:00:00+00:00",
"created_at": "2026-05-12T09:00:00+00:00"
}
],
"links": { "first": "...", "last": "...", "prev": null, "next": null },
"meta": { "current_page": 1, "per_page": 20, "total": 10 }
}| Field | Type | Description |
|---|---|---|
id | integer | Report database ID |
uuid | string (UUID) | Report UUID - use this in report URLs |
score | integer | Overall score (0–100) |
total | integer | Total analyzers run |
passed | integer | Analyzers that passed |
failed | integer | Analyzers with failures |
warnings | integer | Analyzers with warnings |
skipped | integer | Analyzers skipped |
errors | integer | Analyzers that errored |
total_issues | integer | Total issues found across all analyzers |
issues_by_severity | object | Issue counts by severity: critical, high, medium, low, info |
laravel_version | string|null | Laravel version of the analyzed application |
package_version | string|null | ShieldCI package version that ran the analysis |
total_execution_time | float|null | Total analysis duration in seconds |
triggered_by | string|null | How the analysis was triggered (api, webhook, etc.) |
analyzed_at | string|null | ISO 8601 timestamp when analysis ran |
created_at | string|null | ISO 8601 record creation timestamp |
Errors
| Status | Condition |
|---|---|
401 | Missing or invalid token |
403 | Token lacks read ability or no active subscription |
404 | Project not found or user lacks permission to view it |
Get Report
GET/api/v1/reports/{report}Requires ability: read
Returns the full detail for a single report, including per-analyzer results and all issues.
Request
| Header | Value | Required |
|---|---|---|
Authorization | Bearer shieldci_{token} | Yes |
Accept | application/json | Recommended |
| Parameter | Type | Description |
|---|---|---|
report | UUID string | Report UUID (from data[].uuid in the list response) |
curl "https://shieldci.com/api/v1/reports/6ba7b810-9dad-11d1-80b4-00c04fd430c8" \
-H "Authorization: Bearer shieldci_{token}" \
-H "Accept: application/json"Response
Contains all summary fields plus a results array with per-analyzer detail:
{
"data": {
"id": 42,
"uuid": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
"score": 87,
"total": 100,
"passed": 87,
"failed": 8,
"warnings": 3,
"skipped": 2,
"errors": 0,
"total_issues": 11,
"issues_by_severity": { "critical": 0, "high": 1, "medium": 4, "low": 6, "info": 0 },
"laravel_version": "12",
"package_version": "1.2.0",
"total_execution_time": 14.8,
"triggered_by": "api",
"analyzed_at": "2026-05-12T09:00:00+00:00",
"created_at": "2026-05-12T09:00:00+00:00",
"results": [
{
"analyzer_id": "xss-detection",
"analyzer_name": "XSS Detection",
"category": "security",
"status": "failed",
"execution_time": 1.2,
"issues": [
{
"message": "Unescaped user input passed to {!! !!}",
"severity": "high",
"location": { "file": "resources/views/user/profile.blade.php", "line": 42 },
"recommendation": "Use {{ }} for automatic escaping or sanitize the value before output."
}
]
},
{
"analyzer_id": "sql-injection",
"analyzer_name": "SQL Injection",
"category": "security",
"status": "passed",
"execution_time": 0.8,
"issues": []
}
]
}
}results[] fields:
| Field | Type | Description |
|---|---|---|
analyzer_id | string | Analyzer identifier (e.g. xss-detection) |
analyzer_name | string | Human-readable analyzer name |
category | string | Category (security, performance, reliability, etc.) |
status | string | passed, failed, warning, skipped, or error |
execution_time | float|null | Time this analyzer took in seconds |
message | string|null | The analyzer's own summary. When status is error this is the reason it could not run. Stored stripped of control characters and capped at 1000 characters |
issues | array | List of issues found (empty array if none) |
metadata | object | Analyzer descriptors — see below |
results[].metadata fields:
Only the keys below are stored. Anything else in the object is discarded on ingest.
| Field | Type | Description |
|---|---|---|
description | string | What the analyzer checks |
docsUrl | string | Link to this analyzer's documentation |
severity | string | The analyzer's default severity |
timeToFix | integer | Estimated minutes to fix one issue, used for the technical-debt estimate |
exception | string | Class of the throwable that stopped the analyzer. Only present when status is error |
Stack traces are not stored
The package also sends a trace key on errored results. The API accepts it and discards it on ingest — it is not part of the stored contract, so do not build against it. Your CI log already has the full trace, which is where output of that size belongs. Use message and exception to diagnose an analyzer that could not run.
results[].issues[] fields:
| Field | Type | Description |
|---|---|---|
message | string | Description of the issue |
severity | string | critical, high, medium, low, or info |
location | object | {file: string, line: integer} - may be empty if no location available |
recommendation | string|null | Suggested fix |
Errors
| Status | Condition |
|---|---|
401 | Missing or invalid token |
403 | Token lacks read ability or no active subscription |
404 | Report not found, or the report's parent project does not exist |
Delete Report
DELETE/api/v1/reports/{report}Requires ability: write
Permanently deletes a single report.
Request
| Header | Value | Required |
|---|---|---|
Authorization | Bearer shieldci_{token} | Yes |
| Parameter | Type | Description |
|---|---|---|
report | UUID string | Report UUID |
curl -X DELETE "https://shieldci.com/api/v1/reports/6ba7b810-9dad-11d1-80b4-00c04fd430c8" \
-H "Authorization: Bearer shieldci_{token}"Response
{
"message": "Report deleted successfully."
}Errors
| Status | Condition |
|---|---|
401 | Missing or invalid token |
403 | Token lacks write ability, no active subscription, or user lacks permission to delete |
404 | Report not found or the report's parent project does not exist |
Related
- Projects - Manage projects and their API tokens
- Authentication - How to create and use API tokens
- Errors - Full error reference