Policy Documents
Declarations page, policy jacket, endorsement certificate, binder
The @openinsure/documents package generates all insurance documents as HTML. Production PDFs are rendered by the WeasyPrint doc factory, then stored with audit metadata for retrieval, e-signature, and archival.
Policy Documents
Declarations page, policy jacket, endorsement certificate, binder
Sales & Quotes
Quote proposal, premium indication letter, coverage comparison
Certificates
Certificate of Insurance (COI / ACORD 25), MCS-90 motor carrier certificate
Billing
Invoice, installment schedule, check (disbursement)
Claims
Reservation of rights letter, coverage denial, settlement agreement, proof of loss
Compliance
Notice of Cancellation (NOC), non-renewal notice, loss run, bordereaux report
Every document type has a typed builder function that accepts structured data and returns HTML:
import { buildQuoteHTML, buildCOIHTML, buildNOCHTML, buildDecPageHTML, buildEndorsementHTML, buildSettlementHTML, buildLossRunHTML,} from '@openinsure/documents';const html = buildCOIHTML({ insuredName: 'Acme Roofing LLC', policyNumber: 'GL-2025-000001', effectiveDate: '2025-06-01', expirationDate: '2026-06-01', insurer: 'Vermont Mutual Insurance', coverages: [ { type: 'General Liability', occurrence: 1_000_000, aggregate: 2_000_000 }, { type: 'Products & Completed Ops', aggregate: 2_000_000 }, ], certificateHolder: { name: 'Vermont DOT', address: '219 North Main St, Barre, VT 05641', }, additionalInsured: true, producerName: 'Mountain Insurance Agency',});const html = buildQuoteHTML({ submission, ratingAudit, // full factor waterfall from the rating engine validUntil: '2025-07-01', producerName: 'Mountain Insurance Agency', uwName: 'Michael Chen',});Documents are rendered to PDF by the doc factory through renderHTMLToPDFWeasy() in apps/api/src/lib/pdf-renderer.ts.
@openinsure/documentsimport { renderHTMLToPDFWeasy } from '../lib/pdf-renderer';
const pdfBytes = await renderHTMLToPDFWeasy(env, html, { format: 'Letter', margin: '0.5in',});
await storage.put(`policies/${policyId}/dec-page.pdf`, pdfBytes, { customMetadata: { source: 'dec-page', pdfSha256, htmlSha256, generatedAt, },});The Forms Library combines uploaded PDF templates with forms that are generated by the doc factory at bind time.
| Kind | Source of truth | Workbench behavior |
|---|---|---|
| Stored PDF | forms/ and distribution-forms/ objects in document storage | Preview and download the stored blank PDF |
| Generated at Bind | MHC_FORMS_LIBRARY entries with formType: 'html-rendered' | Preview sample HTML through /v1/admin/templates/preview; no blank PDF is downloaded |
Generated forms are data-dependent. For example, Form 802 only renders when one or more drivers are excluded, and state UM/PIP forms render only for matching policy states. In the API, generated rows use synthetic keys such as doc-factory://swd-southwind/driver-exclusion-form-802 and expose templatePreviewId when the workbench can show a sample preview.
OpenInsure uses a self-hosted Documenso instance (openinsure-documenso.fly.dev) for e-signature workflows. Documenso is configured via ESIGN_PROVIDER=documenso in wrangler.toml.
POST /v1/documents/:id/request-signatureAuthorization: Bearer <token>Content-Type: application/json
{ "documentType": "binder", "signatories": [ { "name": "Jane Smith", "email": "jane@acme.com", "role": "insured" }, { "name": "Mountain Insurance Agency", "email": "agent@mountain.com", "role": "producer" } ], "redirectUrl": "https://portal.openinsure.dev/policies/{id}?signed=true"}GET /v1/documents/:id/signature-status# Returns: { status: "pending" | "completed" | "declined", signatories: [...] }Beyond PDFs, the documents package provides tabular exports:
import { exportToCSV, exportToExcel } from '@openinsure/documents';
// Loss run CSV for underwritingconst csv = exportToCSV(lossRunRows, { columns: ['claimNumber', 'dateOfLoss', 'status', 'totalIncurred'], filename: 'loss-run-2025.csv',});
// Bordereaux Excel workbook for carrier submissionconst xlsx = await exportToExcel(bordereaux, { sheets: ['Premium', 'Claims', 'Summary'],});Document writes route through resolveDocsStorage(env) in apps/api/src/lib/storage. The provider hierarchy is:
mhcmga-storage cpx41 Ashburn + mhcmga-storage-box BX41 Falkenstein). Endpoint: storage.openinsure.dev. Seven buckets provisioned: oi-documents, oi-policy-forms, oi-coi, oi-claims, oi-submissions, oi-rate-manuals, oi-backups.oi-documents bucket bound as DOCUMENTS in wrangler.toml. Workers fall back to R2 when the Garage endpoint is unavailable.Uploads, downloads, and deletes all go through this resolver, so product code never hard-codes a provider. Key schema is identical across providers:
policies/{policyId}/dec-page.pdfpolicies/{policyId}/endorsements/{endorsementId}.pdfpolicies/{policyId}/coi/{coiId}.pdfclaims/{claimId}/settlement-agreement.pdfsubmissions/{submissionId}/quote-proposal.pdfDocuments are served through the API at:
GET /v1/documents/{documentId}/downloadPresigned URLs with 24-hour expiry are returned for direct download without proxying through the Worker. Presigns work against both Garage and R2.
src/builders/{document - type}.ts — returns HTML string 2. Export from src/index.tsapps/api/src/routes/documents.ts that calls the builder and stores the resultdocumentType enum in packages/types 5. Write tests in
src/__tests__/ using snapshot testing (compare generated HTML to fixture)