Download OpenAPI specification:
HomePro Backend API for managing homes, home items, photos, support requests, and users.
All protected endpoints require Firebase JWT token in Authorization header:
Authorization: Bearer <firebase-jwt-token>
Photos are organized in S3 with context-based paths:
{home_item_id}/{filename}{home_id}/{filename}{user_id}/{filename}All endpoints support CORS (Cross-Origin Resource Sharing) to enable requests from web browsers.
Supported CORS Headers:
Access-Control-Allow-Origin: Restricted to http://localhost:3000 and https://home-owners.techAccess-Control-Allow-Methods: GET, POST, PATCH, PUT, DELETE, OPTIONSAccess-Control-Allow-Headers: Authorization, Content-Type, X-Requested-WithAccess-Control-Max-Age: 86400 (24 hours preflight cache)Access-Control-Allow-Credentials: true (for authenticated requests)Preflight Requests:
Validates Firebase JWT token and returns user profile with roles. Creates user session and returns user details.
{- "id": "550e8400-e29b-41d4-a716-446655440000",
- "name": "John Doe",
- "roles": "homeowner, admin"
}Home management, statistics, and deletion operations. Includes cascading delete functionality with proper authorization.
Retrieves all homes that the authenticated user has access to, along with comprehensive statistics including item counts, photo counts, note counts, and emergency item counts.
| userId required | string <uuid> Example: userId=550e8400-e29b-41d4-a716-446655440000 UUID of the user whose homes to retrieve |
[- {
- "id": "home-uuid-1",
- "name": "My Beautiful Home",
- "address": "123 Main St, Anytown, ST 12345",
- "role": "owner",
- "created_at": "2025-08-01T10:00:00",
- "updated_at": "2025-08-07T15:30:00",
- "stats": {
- "total_items": 25,
- "total_photos": 48,
- "emergency_items": 3,
- "total_notes": 12
}
}
]Creates a new home for the authenticated user. Important: Users are currently restricted to owning only ONE home. If a user already has a home, this endpoint will return a 409 Conflict error.
Business Rules:
isPrimary: true)Home Ownership:
| name required | string [ 1 .. 255 ] characters Name/title for the home |
| address | string or null <= 500 characters Physical address of the home |
object or null Flexible metadata for home attributes stored as JSONB. Can include any key-value pairs for home characteristics. |
Minimal home creation with just name
{- "name": "My Beautiful Home"
}{- "id": "550e8400-e29b-41d4-a716-446655440000",
- "name": "My Beautiful Home",
- "address": "123 Main Street, Anytown, ST 12345",
- "isPrimary": true,
- "createdAt": "2025-08-11T21:30:00",
- "message": "Home created successfully"
}Permanently deletes a home and all associated data including:
Important:
Cascading Delete Order:
| homeId required | string <uuid> Example: ace55e40-b56d-43c1-b738-5eee8f1ccdf1 UUID of the home to delete |
{- "error": "Missing or invalid Authorization header",
- "code": "UNAUTHORIZED"
}Home inventory item management with CORS support and delete operations. All endpoints support cross-origin requests from web browsers. Delete operations include cascading photo deletion.
Retrieves all items within a home with optional filtering by type and emergency status. Includes photo counts, note counts, and pre-signed URLs for primary photos. Supports pagination for large inventories.
| homeId required | string <uuid> Example: ace55e40-b56d-43c1-b738-5eee8f1ccdf1 UUID of the home |
| type | string (HomeItemType) Enum: "room" "utility_control" "appliance" "structural" "observation" "wiring" "sensor" "other" Example: type=utility_control Filter by item type |
| emergency | boolean Example: emergency=true Filter by emergency status |
| limit | integer [ 1 .. 100 ] Default: 50 Example: limit=25 Maximum number of items to return |
| offset | integer >= 0 Default: 0 Number of items to skip (for pagination) |
[- {
- "id": "d26d981c-0c6e-41ae-b9f9-8a9ad6e66c94",
- "name": "Kitchen Refrigerator",
- "type": "appliance",
- "is_emergency": false,
- "data": {
- "brand": "Samsung",
- "model": "RF28T5001SG",
- "purchaseDate": "2023-01-15",
- "warranty": "2 years"
}, - "created_at": "2025-08-11T12:00:00",
- "photo_count": 1,
- "note_count": 5
}
]Handles CORS preflight requests for the home items endpoint. Browsers automatically send this request before actual POST requests.
| homeId required | string <uuid> Example: ace55e40-b56d-43c1-b738-5eee8f1ccdf1 UUID of the home |
Creates a new item for a specific home. The item will be associated with the home and can store flexible JSONB data for item-specific information.
Supported Item Types:
room - Living spaces (bedroom, kitchen, etc.)utility_control - Valves, switches, breakers appliance - Household appliancesstructural - Structural elements (beams, foundation)observation - Notes and observationswiring - Electrical wiring and componentssensor - Smart sensors and monitoring devicesother - Uncategorized items| homeId required | string <uuid> Example: ace55e40-b56d-43c1-b738-5eee8f1ccdf1 UUID of the home to add the item to |
| name required | string [ 1 .. 255 ] characters Name/title of the home item |
| itemType required | string (HomeItemType) Enum: "room" "utility_control" "appliance" "structural" "observation" "wiring" "sensor" "other" Category of home item:
|
| isEmergency | boolean Default: false Whether this item requires emergency attention |
| data | string or null Additional item data as JSON string (stored as JSONB in database) |
Example of adding a kitchen refrigerator
{- "name": "Kitchen Refrigerator",
- "itemType": "appliance",
- "isEmergency": false,
- "data": "{\"brand\": \"Samsung\", \"model\": \"RF28T5001SG\", \"purchaseDate\": \"2023-01-15\", \"warranty\": \"2 years\"}"
}{- "id": "d26d981c-0c6e-41ae-b9f9-8a9ad6e66c94",
- "homeId": "ace55e40-b56d-43c1-b738-5eee8f1ccdf1",
- "name": "Kitchen Refrigerator",
- "type": "appliance",
- "isEmergency": false,
- "createdAt": "2025-08-11T12:00:00",
- "message": "Home item created successfully"
}Permanently deletes a home item and all its associated photos.
Delete Process:
Authorization:
Important:
| homeId required | string <uuid> Example: ace55e40-b56d-43c1-b738-5eee8f1ccdf1 UUID of the home containing the item |
| itemId required | string <uuid> Example: d26d981c-0c6e-41ae-b9f9-8a9ad6e66c94 UUID of the home item to delete |
{- "error": "Missing or invalid Authorization header",
- "code": "UNAUTHORIZED"
}Photo management with S3 integration, CORS support, and deletion capabilities. File uploads via multipart/form-data with automatic preflight handling. Delete operations remove photos from both database and S3 storage.
Retrieves photos for a specific home or home item with complete metadata and secure pre-signed S3 URLs for image access (valid for 24 hours by default).
Requirements:
homeId or homeItemId must be provided| homeId | string <uuid> Example: homeId=ace55e40-b56d-43c1-b738-5eee8f1ccdf1 UUID of the home (mutually exclusive with homeItemId) |
| homeItemId | string <uuid> Example: homeItemId=d26d981c-0c6e-41ae-b9f9-8a9ad6e66c94 UUID of the home item (mutually exclusive with homeId) |
[- {
- "id": "photo-uuid-1",
- "file_name": "IMG_3372.JPG",
- "caption": null,
- "is_primary": false,
- "created_at": "2025-08-11T15:30:00",
- "home_item": {
- "id": "d26d981c-0c6e-41ae-b9f9-8a9ad6e66c94",
- "name": "Kitchen Refrigerator",
- "type": "appliance"
}, - "uploaded_by": {
- "id": "ace55e40-b56d-43c1-b738-5eee8f1ccdf1",
- "name": "Test User",
- "email": "test@example.com"
}
}
]Handles CORS preflight requests for photo endpoints. Browsers automatically send this request before actual GET/POST requests.
| homeId | string <uuid> UUID of the home (for preflight validation) |
| homeItemId | string <uuid> UUID of the home item (for preflight validation) |
Upload a photo and associate it with either a home or a specific home item.
Upload Flow:
photo{homeId}/{filename} or {homeItemId}/{filename}homeId or homeItemId associationRequirements:
homeId or homeItemId must be provided (mutually exclusive)File Requirements:
photoS3 Storage:
homepro-photos (configurable){homeId}/{original-filename}{homeItemId}/{original-filename}Database Constraint:
Use Cases:
| homeItemId | string <uuid> Example: homeItemId=d26d981c-0c6e-41ae-b9f9-8a9ad6e66c94 UUID of the home item to associate photo with (mutually exclusive with homeId) |
| homeId | string <uuid> Example: homeId=ace55e40-b56d-43c1-b738-5eee8f1ccdf1 UUID of the home to associate photo with (mutually exclusive with homeItemId) |
| photo required | string <binary> Photo file to upload |
Example of uploading a photo file
{ "photo": "[binary file data - IMG_3372.JPG]" }
{- "id": "photo-uuid-generated",
- "homeItemId": "d26d981c-0c6e-41ae-b9f9-8a9ad6e66c94",
- "fileName": "IMG_3372.JPG",
- "s3Key": "d26d981c-0c6e-41ae-b9f9-8a9ad6e66c94/IMG_3372.JPG",
- "contentType": "image/jpeg",
- "caption": null,
- "message": "Photo uploaded successfully",
}Permanently deletes a specific photo from both the database and S3 storage.
Authorization Rules:
Delete Process:
Context-Based S3 Paths:
{home_item_id}/{filename}{home_id}/{filename}{user_id}/{filename}Important:
| photoId required | string <uuid> Example: photo-uuid-1 UUID of the photo to delete |
{- "error": "Missing or invalid Authorization header",
- "code": "UNAUTHORIZED"
}Updates a photo's primary status for its associated context (home item, home, or user). Only one photo per context can be marked as primary at any given time.
Business Rules:
isPrimary: true, all other photos in the same context are automatically unmarkedisPrimary: false, only this photo's primary status is removedContext Types:
Authorization Rules:
Important:
| photoId required | string <uuid> Example: 550e8400-e29b-41d4-a716-446655440000 UUID of the photo to update |
| isPrimary required | boolean Set to true to mark this photo as primary (automatically unmarking other photos in same context). Set to false to remove primary status from this photo. |
Mark this photo as primary (clears other primary photos in same context)
{- "isPrimary": true
}{- "id": "550e8400-e29b-41d4-a716-446655440000",
- "homeItemId": "d26d981c-0c6e-41ae-b9f9-8a9ad6e66c94",
- "fileName": "IMG_3372.JPG",
- "isPrimary": true,
- "message": "Photo primary status updated successfully"
}Note management for homes and home items. Supports observations, todos, questions, and general notes. Features include pinning, soft deletion, and role-based authorization (homeowners and experts). All operations support Firebase authentication and comprehensive audit trails.
Retrieves all notes for a specific home or home item.
Requirements:
homeId or homeItemId must be provided| homeId | string <uuid> Example: homeId=ace55e40-b56d-43c1-b738-5eee8f1ccdf1 UUID of the home (mutually exclusive with homeItemId) |
| homeItemId | string <uuid> Example: homeItemId=d26d981c-0c6e-41ae-b9f9-8a9ad6e66c94 UUID of the home item (mutually exclusive with homeId) |
[- {
- "id": "note-uuid-1",
- "homeId": "ace55e40-b56d-43c1-b738-5eee8f1ccdf1",
- "homeItemId": null,
- "title": "Kitchen Remodel",
- "body": "Consider replacing the countertops with quartz",
- "noteType": "observation",
- "isPinned": true,
- "authorId": "user-uuid-1",
- "createdBy": "user-uuid-1",
- "createdAt": "2025-08-11T10:30:00",
- "updatedBy": null,
- "updatedAt": "2025-08-11T10:30:00"
}
]Creates a new note for a home or home item.
Authorization:
Requirements:
homeId or homeItemId must be providedbody is requiredisPinned is always false at creationauthorId and createdBy are set to authenticated userNote Types:
general - General notes and commentsobservation - Observations and findingstodo - Action items and tasksquestion - Questions that need answers| homeId | string or null <uuid> UUID of the home (mutually exclusive with homeItemId) |
| homeItemId | string or null <uuid> UUID of the home item (mutually exclusive with homeId) |
| title | string or null <= 255 characters Optional title for the note |
| body required | string non-empty Main content of the note (required) |
| noteType | string Default: "general" Enum: "general" "observation" "todo" "question" Type of note (defaults to 'general' if not provided) |
{- "homeId": "ace55e40-b56d-43c1-b738-5eee8f1ccdf1",
- "title": "Kitchen Remodel Ideas",
- "body": "Consider replacing the countertops with quartz. Also check cabinet hinges.",
- "noteType": "observation"
}{- "id": "note-uuid-generated",
- "homeId": "ace55e40-b56d-43c1-b738-5eee8f1ccdf1",
- "homeItemId": null,
- "title": "Kitchen Remodel Ideas",
- "body": "Consider replacing the countertops with quartz",
- "noteType": "observation",
- "isPinned": false,
- "authorId": "user-uuid-1",
- "createdBy": "user-uuid-1",
- "createdAt": "2025-08-11T15:30:00",
- "updatedBy": null,
- "updatedAt": "2025-08-11T15:30:00"
}Updates an existing note's title, body, and/or noteType.
Authorization:
Allowed Updates:
title (optional)body (optional)noteType (optional)Forbidden Updates:
homeId or homeItemIdauthorId or createdByisPinned (use pin/unpin endpoints)| noteId required | string <uuid> Example: note-uuid-1 UUID of the note to update |
| title | string or null <= 255 characters Updated title for the note |
| body | string or null non-empty Updated content of the note |
| noteType | string or null Enum: "general" "observation" "todo" "question" Updated note type |
{- "body": "Updated note content with more details"
}{- "id": "note-uuid-1",
- "homeId": "ace55e40-b56d-43c1-b738-5eee8f1ccdf1",
- "homeItemId": null,
- "title": "Updated Title",
- "body": "Updated body content",
- "noteType": "todo",
- "isPinned": false,
- "authorId": "user-uuid-1",
- "createdBy": "user-uuid-1",
- "createdAt": "2025-08-11T10:30:00",
- "updatedBy": "user-uuid-2",
- "updatedAt": "2025-08-11T16:45:00"
}Soft deletes a note by setting the deleted_at timestamp.
Authorization:
Behavior:
deleted_at to current timestamp| noteId required | string <uuid> Example: note-uuid-1 UUID of the note to delete |
{- "error": "Missing or invalid Authorization header",
- "code": "UNAUTHORIZED"
}Marks a note as pinned. Multiple notes can be pinned per home/home item.
Authorization:
Idempotency:
| noteId required | string <uuid> Example: note-uuid-1 UUID of the note to pin |
{- "id": "note-uuid-1",
- "homeId": "ace55e40-b56d-43c1-b738-5eee8f1ccdf1",
- "homeItemId": null,
- "title": "Important Note",
- "body": "This is an important note",
- "noteType": "general",
- "isPinned": true,
- "authorId": "user-uuid-1",
- "createdBy": "user-uuid-1",
- "createdAt": "2025-08-11T10:30:00",
- "updatedBy": "user-uuid-2",
- "updatedAt": "2025-08-11T17:00:00"
}Removes the pinned status from a note.
Authorization:
Idempotency:
| noteId required | string <uuid> Example: note-uuid-1 UUID of the note to unpin |
{- "id": "note-uuid-1",
- "homeId": "ace55e40-b56d-43c1-b738-5eee8f1ccdf1",
- "homeItemId": null,
- "title": "Important Note",
- "body": "This is an important note",
- "noteType": "general",
- "isPinned": false,
- "authorId": "user-uuid-1",
- "createdBy": "user-uuid-1",
- "createdAt": "2025-08-11T10:30:00",
- "updatedBy": "user-uuid-2",
- "updatedAt": "2025-08-11T17:15:00"
}Retrieves support requests based on user permissions and filters. Includes full request lifecycle information and assigned expert details.
| status | string (SupportRequestStatus) Enum: "open" "in_progress" "resolved" "closed" "cancelled" Example: status=open Filter by request status |
| homeId | string <uuid> Filter by home ID |
[- {
- "id": "support-uuid-1",
- "homeowner_id": "user-uuid-homeowner",
- "home_id": "home-uuid-1",
- "title": "Kitchen Sink Leak Repair",
- "description": "Main shutoff valve under kitchen sink is leaking.",
- "status": "open",
- "priority": "medium",
- "assigned_expert_id": "user-uuid-expert",
- "created_at": "2025-08-08T09:00:00",
- "updated_at": "2025-08-08T09:15:00"
}
]Creates a new support request for home services. Automatically assigns to appropriate experts based on request type and location.
| homeId | string or null <uuid> Associated home ID |
| title required | string [ 1 .. 200 ] characters Brief title of the support request |
| description required | string [ 1 .. 2000 ] characters Detailed description of the issue |
| priority | string (SupportRequestPriority) Enum: "low" "medium" "high" "urgent" Priority level of the support request |
{- "homeId": "home-uuid-1",
- "title": "Kitchen Sink Leak Repair",
- "description": "Main shutoff valve under kitchen sink is leaking. Need urgent repair.",
- "priority": "high"
}{- "id": "support-uuid-1",
- "title": "Kitchen Sink Leak Repair",
- "status": "open",
- "created_at": "2025-08-08T09:00:00"
}