Introduction
Many Property Management Systems host listing images on their own servers, which can result in slow load times and unreliable availability. The Image CDN feature solves this by automatically downloading PMS images, uploading them to an AWS S3 bucket, and serving them through a CloudFront CDN.
When Image CDN is enabled for an integration definition, every listing sync will detect new or changed images and queue them for CDN upload in the background. Listing API responses are then transparently enhanced with CDN URLs, falling back to original PMS URLs if a CDN copy is not yet available.
Image CDN is an opt-in feature controlled at the integration definition
level. It is disabled by default and must be explicitly enabled per provider.
How It Works
The Image CDN feature follows this flow:
- Listing sync runs — The sync service fetches listing data from the PMS, including thumbnail and gallery image URLs.
- Image detection — If CDN is enabled, the sync service compares the current PMS image URLs against previously stored records and identifies new or changed images.
- Upload queueing — New images are queued as background tasks (
IMAGE_CDN_UPLOAD) for asynchronous processing.
- CDN upload — Each queued image is downloaded from the PMS, validated, hashed, and uploaded to S3 with a CloudFront distribution in front of it.
- URL replacement — When listing data is fetched via the API, CDN URLs are transparently substituted in place of original PMS URLs.
Image Storage Structure
Images are stored in S3 with the following key structure:
{workspaceId}/{listingId}/thumbnail_{hash}.{ext}
{workspaceId}/{listingId}/gallery/{position}_{hash}.{ext}
The content hash in the filename enables automatic deduplication — if the same image is uploaded again, it overwrites the existing file at the same key.
The CDN supports the following image formats:
Images are validated by checking file signatures (magic bytes) before upload. Images larger than 50 MB are skipped.
Enabling Image CDN
To enable Image CDN for a specific provider in your workspace, use the toggle endpoint:
PATCH /api/v1/integration-definition/{provider}/images-cdn
{
"enableImagesCDN": true
}
A successful response returns the updated integration definition:
{
"id": "uuid",
"name": "Hostaway",
"provider": "HOSTAWAY",
"enableImagesCDN": true,
"createdAt": "2025-01-01T00:00:00.000Z",
"updatedAt": "2025-06-01T12:00:00.000Z"
}
Once enabled, the next listing sync for any integration account under that provider will begin queueing image uploads automatically.
Disabling Image CDN
To disable, send the same request with enableImagesCDN set to false:
{
"enableImagesCDN": false
}
When disabled:
- No new images will be queued for upload.
- Existing CDN URLs remain valid and continue to be served until they expire or are cleaned up.
- Listing API responses revert to returning original PMS image URLs.
Listing Response Behavior
When Image CDN is enabled and images have been uploaded, the listing API responses are automatically enhanced:
| Field | Behavior |
|---|
thumbnailURL | Replaced with CDN URL if available, otherwise falls back to PMS URL |
pictures | Gallery URLs replaced with CDN URLs where available, PMS URLs as fallback |
This enhancement is transparent — the response schema does not change. Consumers of the API do not need any code changes to benefit from CDN-served images.
Image uploads are processed asynchronously. After enabling CDN for the first
time, it may take one or more sync cycles before all images are available on
the CDN.
Image Lifecycle
New Listings
When new listings are synced and CDN is enabled, their thumbnail and gallery images are automatically queued for upload during the sync process.
Updated Images
If a PMS changes an image URL for an existing listing, the new URL is detected during the next sync and queued for upload. The original ListingImage record is preserved alongside the new one.
Deleted Listings
When listings are deleted (for example, when removing an integration account), associated CDN images are cleaned up from both S3 and the database. The ListingImage records cascade-delete when the parent listing is removed.
Data Model
The feature introduces a ListingImage table that tracks the relationship between original PMS URLs and their CDN counterparts:
| Field | Type | Description |
|---|
| id | UUID | Unique identifier |
| listingID | UUID | Reference to the parent listing |
| originalURL | string | The original image URL from the PMS |
| cdnURL | string | The CDN URL (null if not yet uploaded) |
| imageHash | string | MD5 hash of the image content for change detection |
| imageType | enum | THUMBNAIL or GALLERY |
| position | number | Order in the gallery (0 for thumbnail) |
| lastCheckedAt | timestamp | When the image was last verified |
| failureReason | string | Error message if upload failed (null on success) |
| createdAt | timestamp | Record creation time |
| updatedAt | timestamp | Last update time |
Error Handling and Fallbacks
The CDN feature is designed to be resilient:
- PMS image returns 404: The original URL is preserved and the
ListingImage record is marked with a failure reason. The listing API continues to return the original URL.
- Image too large: Images exceeding 50 MB are skipped. The original PMS URL is used.
- Invalid image format: Non-image files are rejected. The original URL is retained.
- S3 upload fails: The task is retried automatically. If all retries fail, the failure is logged and the original URL is served.
- CDN enhancement fails: If the enhancement step fails for any reason, the listing is returned with its original PMS URLs — no data is lost.
API Reference