Property Images API
Upload, manage, and reorder property listing images. Images are stored on Cloudflare R2 and served via Image Transformations.
Upload Flow
Image upload is a two-step process:
- Presign — get a presigned upload URL from the API
- Upload — PUT the file directly to the presigned URL (client → R2, no proxy)
- Confirm — tell the API the upload succeeded, creating the database record
List Images
GET /api/v1/properties/:id/imagesReturns all images for a property, ordered by display order.
Response:
{
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"url": "https://images.rentalot.ai/images/user123/prop456/img789.jpg",
"altText": "Living room with hardwood floors",
"order": 0
}
]
}Get Presigned Upload URL
POST /api/v1/properties/:id/images/presignRequest Body:
{
"fileName": "living-room.jpg",
"contentType": "image/jpeg",
"sizeBytes": 2048576
}| Field | Type | Description |
|---|---|---|
fileName | string | Original filename (used for extension extraction) |
contentType | string | image/jpeg, image/png, image/webp, or image/heic |
sizeBytes | number | File size in bytes (max 10MB) |
Response:
{
"uploadUrl": "https://r2.example.com/presigned-put-url...",
"r2Key": "images/user123/prop456/abc-def.jpg",
"maxImages": 20
}Upload the file via PUT to the uploadUrl, then call the confirm endpoint.
Confirm Upload
POST /api/v1/properties/:id/images/confirmCreates the database record after a successful upload. Supports Idempotency-Key header.
Request Body:
{
"r2Key": "images/user123/prop456/abc-def.jpg",
"contentType": "image/jpeg",
"sizeBytes": 2048576,
"altText": "Living room with hardwood floors"
}Returns the created image object.
Delete Images
DELETE /api/v1/properties/:id/imagesDelete one or more images by ID. Removes from both database and R2 storage.
Request Body:
{
"imageIds": ["550e8400-e29b-41d4-a716-446655440000"]
}Returns { "deleted": 1 }.
Reorder Images
PATCH /api/v1/properties/:id/images/reorderSet the display order. The first ID in the array gets order 0, second gets 1, etc.
Request Body:
{
"imageIds": [
"img-id-for-order-0",
"img-id-for-order-1",
"img-id-for-order-2"
]
}Returns { "ok": true }.
Notes
- Tier-limited — the number of images per property depends on your plan (check
maxImagesin the presign response). - Allowed types: JPEG, PNG, WebP, HEIC. Max 10MB per image.
- Images are served via Cloudflare Image Transformations for automatic resizing and format optimization.