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_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxKeys 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_idmatches 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_id | string | Your stable ID. Used for idempotent updates. |
entry_code | string | ASHI library entry code (e.g. "ASHI-STR-FND-01"). When provided, missing fields are hydrated from the matching library entry. |
system | string | Top-level system (Roofing, Electrical, etc.). |
category | string | Sub-category within the system. |
item_name | string | Short label (e.g. "Composition shingles"). |
location | string | Where in the property (e.g. "Front slope"). |
original_report_text | string | Verbatim text from the inspection report. |
recommendation_text | string | What the inspector recommends. |
recommendation_type | enum | repair | further_evaluation | maintenance | monitor | safety | upgrade | informational |
priority | enum | urgent_safety | repair_recommended | further_evaluation | maintenance_monitor | informational |
page_number | int | Page in the source PDF. |
photo_refs | string[] | 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
401 | Missing/invalid Authorization header. |
403 | Key revoked, expired, or missing required scope. |
400 | Invalid JSON, missing required fields, or unsupported bridge_contract_version. |
500 | Internal 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.