HomeFile Portal · Developer Docs

Bridge API

The Bridge API lets inspection software (PIS, Spectora, HomeGauge, or custom tools) post structured report data directly into HomeFile Portal. Each integration uses an API key issued by a HomeFile platform admin.

Authentication

Every request includes a bearer token in the Authorization header:

Authorization: Bearer hfp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Keys are issued from the HomeFile admin panel and shown only once at creation. Each key is scoped to one organization and optionally one report source.

Endpoint: POST /api/bridge/import

Submit a property + report + findings payload. The portal will:

  • Find or create the property by address_line_1
  • Find or create the report by (report_source_id, source_report_id) — re-posts update the existing report
  • For each finding: insert if new, update if source_finding_id matches an existing one

Findings are imported with visible_to_client = false. A HomeFile admin reviews and toggles visibility before clients see them.

Request body (canonical bridge contract v1)

{
  "bridge_contract_version": "v1",
  "property": {
    "address_line_1": "123 Maple Street",
    "address_line_2": null,
    "city": "Springfield",
    "state": "OR",
    "zip": "97477",
    "property_type": "single_family",
    "year_built": 1985
  },
  "report": {
    "source_report_id": "PIS-RPT-12345",
    "title": "Residential Inspection — 123 Maple",
    "report_type": "buyer_inspection",
    "inspection_date": "2026-06-01",
    "inspector_name": "Casey Hill",
    "inspection_company": "Hill Inspections"
  },
  "findings": [
    {
      "source_finding_id": "PIS-F-1",
      "system": "Roofing",
      "category": "Roof Coverings",
      "item_name": "Composition shingles",
      "location": "Front slope",
      "original_report_text": "Several shingles missing at front slope ridge.",
      "recommendation_text": "Repair missing shingles to prevent water intrusion.",
      "recommendation_type": "repair",
      "priority": "repair_recommended",
      "page_number": 14,
      "photo_refs": []
    }
  ]
}

Finding fields

source_finding_idstringYour stable ID. Used for idempotent updates.
entry_codestringASHI library entry code (e.g. "ASHI-STR-FND-01"). When provided, missing fields are hydrated from the matching library entry.
systemstringTop-level system (Roofing, Electrical, etc.).
categorystringSub-category within the system.
item_namestringShort label (e.g. "Composition shingles").
locationstringWhere in the property (e.g. "Front slope").
original_report_textstringVerbatim text from the inspection report.
recommendation_textstringWhat the inspector recommends.
recommendation_typeenumrepair | further_evaluation | maintenance | monitor | safety | upgrade | informational
priorityenumurgent_safety | repair_recommended | further_evaluation | maintenance_monitor | informational
page_numberintPage in the source PDF.
photo_refsstring[]Storage paths returned by /api/bridge/upload-photo.

Minimum required: original_report_text, recommendation_text, or entry_code. All other fields are optional. Unknown fields are silently ignored (forward-compatible).

Endpoint: POST /api/bridge/upload-photo

Upload an inspection photo and receive a storage path to reference in a finding’s photo_refs array. Bridges never write to storage directly.

Send as multipart/form-data with a single file field. Optional fields: source_finding_id (to label the upload) and caption.

curl -X POST https://your-portal.com/api/bridge/upload-photo \
  -H "Authorization: Bearer hfp_xxxxx" \
  -F "file=@photo.jpg" \
  -F "source_finding_id=PIS-F-1" \
  -F "caption=Front slope, missing shingles"

# Response:
# { "ok": true, "storage_path": "bridge/<org>/<uuid>.jpg", ... }

Limits: 15 MB per photo. Accepted types: JPEG, PNG, WebP, HEIC, HEIF. Use the returned storage_path verbatim in subsequent photo_refs arrays.

Tip: use entry_code to skip text duplication

The simplest payload for a vendor that uses the ASHI library is just an entry code plus your stable ID:

{
  "source_finding_id": "PIS-F-42",
  "entry_code": "ASHI-ROOF-COV-04",
  "location": "Front slope",
  "photo_refs": ["bridge/<org>/<uuid>.jpg"]
}

The portal hydrates system, category, item_name, original_report_text, recommendation_type, and priority from the library entry. The bridge can still override any of these by sending them explicitly.

Response 200

{
  "ok": true,
  "property_id": "uuid",
  "report_id": "uuid",
  "findings_imported": 47,
  "findings_updated": 3,
  "findings_skipped": 1,
  "parse_errors": [
    { "index": 12, "reason": "Each finding needs at least original_report_text or recommendation_text.", "raw": {...} }
  ]
}

Error responses

401Missing/invalid Authorization header.
403Key revoked, expired, or missing required scope.
400Invalid JSON, missing required fields, or unsupported bridge_contract_version.
500Internal error — retry safe (idempotency keys protect you).

Idempotency

The bridge guarantees safe re-posts. Identify reports with source_report_id and findings with source_finding_id; re-submitting the same payload will update in place rather than create duplicates.

What the portal owns vs. what the bridge owns

The bridge produces structured data. The portal:

  • Stores it
  • Lets admin classify, edit, and tag findings
  • Generates client-friendly summaries (with optional LLM assist)
  • Controls client/agent visibility
  • Generates packets (Repair Request, Reinspection, etc.)

See handoffs/12-bridge-vs-portal-responsibilities.md for the full breakdown.

Pulling content from the ASHI library

Instead of writing your own observation text, you can reference entries in the universal ASHI Residential library. Each entry has a stable code like ASHI-STR-FND-01. Future bridge versions will let you POST { entry_code, observation_text?, photo_refs? } and the portal will hydrate severity, recommendation type, output text, and system/category automatically.

The ASHI library covers all 11 ASHI Standards of Practice categories and 1,141 pre-written entries. Reach out for the entry CSV if you’re building a new integration.