LintPDF LintPDF

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

FieldTypeRequiredDefaultDescription
htmlformatNoBranded interactive landing page. Served at /r/{token} (no extension). Plans: Free+. Delivery: URL only.
pdfformatNoPrint-ready PDF report with summary page and findings detail. Served at /r/{token}.pdf. Plans: Starter+. Delivery: URL only.
jsonformatNoStructured 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.
xmlformatNoSame 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_pdfformatNoOriginal 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_markupformatNoOriginal 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).

FieldTypeRequiredDefaultDescription
formats(FormatName | { format: FormatName; return?: "url" | "inline" | "both" })[]YesOutput 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_daysintegerNotenant 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_tostring[]NoIf provided, LintPDF emails the share URLs to these addresses (tenant-branded unless branding=anonymous).
branding"anonymous" | "lintpdf" | uuidNoFreezes the brand state at mint time. Overrides the tenant default.
detail_level"executive"|"standard"|"comprehensive"NostandardNarrative density in PDF/HTML — executive is summary-only, comprehensive walks every finding. Ignored by JSON/XML.
summary_page"prepend"|"only"|"off"NoprependControls 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:

FieldTypeRequiredDefaultDescription
Filename (anonymous)stringNopreflight-<short-id>.pdf — no tenant slug, no brand reference.
Filename (tenant)stringNo{tenant-slug}-<short-id>.pdf — derived from the BrandProfile.
Filename (lintpdf)stringNolintpdf-<short-id>.pdf.
PDF AuthormetadataNoAnonymous: empty. Tenant: BrandProfile.company_name. LintPDF: 'LintPDF'.
PDF ProducermetadataNoAnonymous: generic 'Preflight Report'. Otherwise: 'LintPDF <version>'.
PDF CreatormetadataNoAnonymous: generic 'Preflight Report'. Otherwise: tenant or LintPDF brand string.
Footer / headerrenderNoAnonymous: 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...