Report Formats
LintPDF mints reports as immutable tokens. Each token binds a format (PDF, HTML, JSON, XML, optionally annotated PDF) and a frozen branding state. Consume reports via public share URLs or the authenticated list endpoint. See the Share Links and Branding & Anonymous Output pages for the full workflow.
Available formats
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
html | format | No | — | Branded interactive landing page. Served at /r/{token} (no extension). Plans: Free+. Delivery: URL only. |
pdf | format | No | — | Print-ready PDF report with summary page and findings detail. Served at /r/{token}.pdf. Plans: Starter+. Delivery: URL only. |
json | format | No | — | Structured findings matching the LintPDF v1 import schema — re-importable via preflight_source=external, external_format=lintpdf_json. Served at /r/{token}.json. Plans: Free+. Supports return="inline" — parsed object embedded in the response body as reports[].data. |
xml | format | No | — | Same field taxonomy as JSON, for Switch / MIS / legacy XML consumers. Served at /r/{token}.xml. Plans: Starter+. Supports return="inline" — raw XML string embedded in reports[].data. |
annotated_pdf | format | No | — | Original PDF with findings drawn as overlays on the source pages. Served at /r/{token}.pdf. Plans: Scale+ (silently skipped if the original PDF cannot be re-fetched from object storage). Delivery: URL only. |
annotated_pdf_markup | format | No | — | Original PDF stamped with the reviewer's interactive-viewer markup (rects, circles, arrows, freehand strokes, numbered sticky-note pins) plus an appendix page that resolves each note number to its body and full comment thread. Served at /r/{token}.pdf. Plans: Scale+. Silently skipped if no annotations exist. Delivery: URL only. |
Minting knobs
Call POST /api/v1/jobs/{job_id}/reports with the fields below. Every knob has a sensible default, so the minimum request is { "formats": ["pdf"] }. Each formats entry may be a bare format string (back-compat — resolves to return: "url") or a { format, return } spec to request inline or both (text formats only).
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
formats | (FormatName | { format: FormatName; return?: "url" | "inline" | "both" })[] | Yes | — | Output formats to mint. return="url" (default) gives a hosted share link. return="inline" embeds parsed JSON / raw XML directly in the response body and skips both object storage and token minting. return="both" does both. Inline is rejected with 422 on binary formats (pdf, annotated_pdf, annotated_pdf_markup, html). Default: ["html", "pdf"]. |
expiry_days | integer | No | tenant default (typically 7–30) | Token lifetime in days. After expiry the public URLs return 410 Gone. Ignored for inline-only rows because no token is minted. |
email_to | string[] | No | — | If provided, LintPDF emails the share URLs to these addresses (tenant-branded unless branding=anonymous). |
branding | "anonymous" | "lintpdf" | uuid | No | — | Freezes the brand state at mint time. Overrides the tenant default. |
detail_level | "executive"|"standard"|"comprehensive" | No | standard | Narrative density in PDF/HTML — executive is summary-only, comprehensive walks every finding. Ignored by JSON/XML. |
summary_page | "prepend"|"only"|"off" | No | prepend | Controls the PDF summary page placement. Ignored by JSON/XML. |
Idempotent mints (opt-in)
Send an Idempotency-Key header (max 255 characters) and the engine derives each token deterministically from sha256(tenant_id + key + format). A subsequent mint with the same key reuses the existing artifact instead of regenerating and re-uploading — safe to retry, CDN-friendly, and survives transient failures without creating duplicate share links. The header is per-tenant scoped, so a client-side key cannot collide with another tenant's reports.
JSON schema
The json format returns the full job payload plus frozen source metadata. Import this shape directly using the native LintPDF v1 import schema.
{
"schema_version": "1",
"job_id": "d4e5f6a7-...",
"profile_id": "lintpdf-default",
"preflight_source": "engine",
"external_format": null,
"summary": {
"passed": false,
"total_findings": 7,
"error_count": 1,
"warning_count": 4,
"advisory_count": 2,
"page_count": 12,
"file_size_bytes": 1834221
},
"document": {
"pdf_version": "1.7",
"page_count": 12,
"is_encrypted": false,
"conformance": "PDF/X-4"
},
"findings": [
{
"inspection_id": "LPDF_FONT_001",
"severity": "error",
"message": "Font 'Helvetica' is not embedded",
"page_num": 1,
"object_id": "F1",
"object_type": "font",
"iso_clause": "ISO 32000-2:2020 9.6",
"category": "fonts",
"source": "engine",
"bbox": [72.0, 720.0, 540.0, 740.0],
"details": { "font_name": "Helvetica" }
}
],
"metadata": { "pdf_version": "1.7", "page_count": 12, "...": "..." },
"duration_ms": 4321
}XML schema
XML reports follow the same field taxonomy as JSON in the urn:lintpdf:preflight:1.0 namespace. Use them for integrations that already consume XML preflight output (Switch, legacy MIS).
<?xml version="1.0" encoding="UTF-8"?>
<PreflightReport xmlns="urn:lintpdf:preflight:1.0" schemaVersion="1">
<JobId>d4e5f6a7-...</JobId>
<ProfileId>lintpdf-default</ProfileId>
<DurationMs>4321</DurationMs>
<PreflightSource>engine</PreflightSource>
<Summary>
<Passed>false</Passed>
<TotalFindings>7</TotalFindings>
<ErrorCount>1</ErrorCount>
<WarningCount>4</WarningCount>
<AdvisoryCount>2</AdvisoryCount>
<PageCount>12</PageCount>
<FileSizeBytes>1834221</FileSizeBytes>
</Summary>
<Document>
<PdfVersion>1.7</PdfVersion>
<IsEncrypted>false</IsEncrypted>
<Conformance>PDF/X-4</Conformance>
</Document>
<Findings>
<Finding>
<InspectionId>LPDF_FONT_001</InspectionId>
<Severity>error</Severity>
<Message>Font 'Helvetica' is not embedded</Message>
<PageNum>1</PageNum>
<ObjectId>F1</ObjectId>
<ObjectType>font</ObjectType>
<IsoClause>ISO 32000-2:2020 9.6</IsoClause>
<Category>fonts</Category>
<Source>engine</Source>
<BBox>72.0 720.0 540.0 740.0</BBox>
<Details>
<Detail key="font_name">Helvetica</Detail>
</Details>
</Finding>
</Findings>
</PreflightReport>PDF & HTML reports — branding resolution
The PDF and HTML formats honour branding at mint time. Anonymous mode is the strongest — it strips tenant branding, LintPDF branding, PDF document metadata (Author/Producer/Creator), and uses a neutral filename:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
Filename (anonymous) | string | No | — | preflight-<short-id>.pdf — no tenant slug, no brand reference. |
Filename (tenant) | string | No | — | {tenant-slug}-<short-id>.pdf — derived from the BrandProfile. |
Filename (lintpdf) | string | No | — | lintpdf-<short-id>.pdf. |
PDF Author | metadata | No | — | Anonymous: empty. Tenant: BrandProfile.company_name. LintPDF: 'LintPDF'. |
PDF Producer | metadata | No | — | Anonymous: generic 'Preflight Report'. Otherwise: 'LintPDF <version>'. |
PDF Creator | metadata | No | — | Anonymous: generic 'Preflight Report'. Otherwise: tenant or LintPDF brand string. |
Footer / header | render | No | — | Anonymous: empty. Tenant: BrandProfile.footer_text + logo. LintPDF: product mark. |
JSON and XML formats are identical regardless of branding mode — only document metadata can carry brand identifiers, and structured payloads don't embed any.
Consuming a report URL
# Interactive HTML landing (share with anyone)
GET https://reports.lintpdf.com/r/rpt_01HXY...
# PDF download (?download=1 forces Content-Disposition: attachment)
GET https://reports.lintpdf.com/r/rpt_01HXY....pdf?download=1
# Structured JSON (LintPDF v1 import schema, public)
GET https://reports.lintpdf.com/r/rpt_01HXY....json
# Legacy XML (same taxonomy as JSON, public)
GET https://reports.lintpdf.com/r/rpt_01HXY....xml
# Findings-only JSON via the API host (alias of /r/{token}.json)
GET https://api.lintpdf.com/api/v1/reports/tokens/rpt_01HXY.../findings
# Revoke (authenticated)
DELETE https://api.lintpdf.com/api/v1/jobs/{job_id}/reports/rpt_01HXY...