Photo Upload Guide
Learn how to upload interior and exterior photos for AI enhancement.
Overview
Photo uploads use a two-step process: first upload files to get signed URLs, then create your order with those file references. This approach supports files up to 50MB and bypasses serverless limits.
Service Type Requirements
- • exterior: No photos needed - uses public imagery sources automatically
- • interior: Must upload interior photos
- • both: Must upload interior photos; exterior uses public imagery sources
Supported Formats
- • File Types: JPEG (.jpg/.jpeg), PNG, WebP, HEIC (auto-converted)
- • Max File Size: 50MB per photo
- • Recommended Resolution: 2000x1500 pixels or higher
- • Best Practice: Keep individual photos under 5MB for optimal performance
Two-Step Upload Process
Upload interior photos with the same enhancements applied to all:
// Step 1: Create upload session
const sessionResponse = await fetch('https://www.quickhome.ai/api/v1/uploads/sessions', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
serviceType: 'interior',
files: [
{ role: 'interior', filename: 'living-room.jpg', mimeType: 'image/jpeg' },
{ role: 'interior', filename: 'kitchen.jpg', mimeType: 'image/jpeg' },
{ role: 'interior', filename: 'bedroom.jpg', mimeType: 'image/jpeg' }
]
})
});
const { uploadSessionId, files } = await sessionResponse.json();
// Step 2: Upload each file to storage
for (let i = 0; i < files.length; i++) {
const file = files[i];
const fileBlob = [livingRoomFile, kitchenFile, bedroomFile][i];
await fetch(file.uploadUrl, {
method: 'PUT',
body: fileBlob,
headers: { 'Content-Type': file.mimeType }
});
}
// Step 3: Create order with file references
const orderResponse = await fetch('https://www.quickhome.ai/api/v1/orders', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
address: '266 Dana Point Ave, Ventura, CA 93004, USA',
serviceType: 'interior',
uploadSessionId: uploadSessionId,
interiorPhotos: files.map(f => ({
filePath: f.storagePath,
fileName: f.filename,
index: f.index
})),
interiorEnhancements: ['virtual_staging', 'hdr_enhancement']
})
});
const result = await orderResponse.json();
console.log('Order created:', result.jobId);Per-Image Enhancement Control
For advanced use cases, specify different enhancements for each photo using photoConfigs:
// Step 1: Create upload session
const sessionResponse = await fetch('https://www.quickhome.ai/api/v1/uploads/sessions', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
serviceType: 'interior',
files: [
{ role: 'interior', filename: 'empty-living-room.jpg', mimeType: 'image/jpeg' },
{ role: 'interior', filename: 'messy-kitchen.jpg', mimeType: 'image/jpeg' },
{ role: 'interior', filename: 'furnished-bedroom.jpg', mimeType: 'image/jpeg' }
]
})
});
const { uploadSessionId, files } = await sessionResponse.json();
// Step 2: Upload files
await fetch(files[0].uploadUrl, { method: 'PUT', body: emptyLivingRoom });
await fetch(files[1].uploadUrl, { method: 'PUT', body: messyKitchen });
await fetch(files[2].uploadUrl, { method: 'PUT', body: furnishedBedroom });
// Step 3: Create order with per-image enhancements
const photoConfigs = [
{ photoIndex: 0, photoType: 'interior', enhancements: ['virtual_staging'] },
{ photoIndex: 1, photoType: 'interior', enhancements: ['declutter', 'hdr_enhancement'] },
{ photoIndex: 2, photoType: 'interior', enhancements: ['furniture_removal'] }
];
const response = await fetch('https://www.quickhome.ai/api/v1/orders', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
address: '266 Dana Point Ave, Ventura, CA 93004, USA',
serviceType: 'interior',
uploadSessionId: uploadSessionId,
interiorPhotos: files.map(f => ({
filePath: f.storagePath,
fileName: f.filename,
index: f.index
})),
photoConfigs: photoConfigs
})
});Exterior Photo Upload (Optional)
By default, exterior photos are fetched from public imagery sources. However, you can optionally upload your own professional exterior photos:
// Step 1: Create upload session
const sessionResponse = await fetch('https://www.quickhome.ai/api/v1/uploads/sessions', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
serviceType: 'exterior',
files: [
{ role: 'exterior', filename: 'front-view.jpg', mimeType: 'image/jpeg' },
{ role: 'exterior', filename: 'side-view.jpg', mimeType: 'image/jpeg' }
]
})
});
const { uploadSessionId, files } = await sessionResponse.json();
// Step 2: Upload files
await fetch(files[0].uploadUrl, { method: 'PUT', body: frontViewFile });
await fetch(files[1].uploadUrl, { method: 'PUT', body: sideViewFile });
// Step 3: Create order
const response = await fetch('https://www.quickhome.ai/api/v1/orders', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
address: '266 Dana Point Ave, Ventura, CA 93004, USA',
serviceType: 'exterior',
uploadSessionId: uploadSessionId,
exteriorPhotos: files.map(f => ({
filePath: f.storagePath,
fileName: f.filename,
index: f.index
})),
exteriorEnhancements: ['sky_enhancement', 'grass_enhancement']
})
});Browser Upload Example
Example HTML for uploading photos from a browser:
<form id="orderForm">
<input type="text" id="address" placeholder="Property Address" required />
<select id="serviceType">
<option value="interior">Interior</option>
<option value="exterior">Exterior</option>
<option value="both">Both</option>
</select>
<input type="file" id="photos" multiple accept="image/jpeg,image/png,image/webp,image/heic" />
<button type="submit">Create Order</button>
</form>
<script>
document.getElementById('orderForm').addEventListener('submit', async (e) => {
e.preventDefault();
const address = document.getElementById('address').value;
const serviceType = document.getElementById('serviceType').value;
const files = Array.from(document.getElementById('photos').files);
// Step 1: Create upload session
const sessionResponse = await fetch('https://www.quickhome.ai/api/v1/uploads/sessions', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
serviceType: serviceType,
files: files.map(f => ({
role: 'interior',
filename: f.name,
mimeType: f.type
}))
})
});
const { uploadSessionId, files: uploadFiles } = await sessionResponse.json();
// Step 2: Upload each file
for (let i = 0; i < files.length; i++) {
await fetch(uploadFiles[i].uploadUrl, {
method: 'PUT',
body: files[i],
headers: { 'Content-Type': files[i].type }
});
}
// Step 3: Create order
const orderResponse = await fetch('https://www.quickhome.ai/api/v1/orders', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
address: address,
serviceType: serviceType,
uploadSessionId: uploadSessionId,
interiorPhotos: uploadFiles.map(f => ({
filePath: f.storagePath,
fileName: f.filename,
index: f.index
})),
interiorEnhancements: ['virtual_staging']
})
});
const result = await orderResponse.json();
console.log('Order created:', result.jobId);
});
</script>Best Practices
- • Use high-resolution photos (2000x1500px or higher) for best results
- • Ensure photos are well-lit and in focus
- • Upload photos in the correct orientation
- • For virtual staging, provide empty room photos
- • For decluttering, capture the full room including clutter
- • Test with a single photo before batch processing
Next Steps
- • See the complete API reference
- • Learn how to check job status
- • Try the Quickstart guide