PropertyPixel Docs

Uploading photos

Four ways to get listing photos into a project.

Every photo belongs to a project. Create one first (create_project, or POST /v1/projects).

All routes accept JPEG, PNG, WebP, HEIC and HEIF files up to 25 MB each, and a project holds up to 100 photos. HEIC and HEIF are converted to JPEG, and large photos are resized to a 2048px long edge, as in the web app.

MethodUse it whenMCPREST
Image URLsThe photos are online (CDN, listing site, Dropbox)✓✓
ChatGPT filesThe user attached photos in ChatGPT✓
Upload linkThe photos are on someone's phone or computer✓✓
Signed uploadYour script has the files locally✓

Image URLs

Pass up to 25 public https URLs to add_photos (POST /v1/projects/{project_id}/photos):

{
  "image_urls": ["https://example.com/front.jpg", "https://www.dropbox.com/s/abc/kitchen.jpg?dl=0"]
}

Public Dropbox and Google Drive share links are converted to direct downloads. URLs must be reachable without signing in; private and internal addresses are refused. The response lists the new photos and a failed entry, with a reason, for each URL that couldn't be used.

ChatGPT files

In ChatGPT, photos attached to a message are passed to add_photos as files, and PropertyPixel downloads them. If ChatGPT can't hand over a file, PropertyPixel shows its upload widget instead.

create_upload_link (POST /v1/projects/{project_id}/upload-links) returns a private url and a QR code (qr_svg). Open the link on a phone or computer to add photos without signing in.

  • A link works for 2 hours and only for that project.
  • Photos appear in the project as they upload.
  • get_project shows the latest link's upload_link.status (waiting, receiving, done or expired) and photos_received.
  • When the person finishes, PropertyPixel sends the upload.completed webhook.

Anyone with the link can add photos to that project until it expires, so share it only with the person taking the photos.

Signed upload

For files on disk, use the three-step signed upload (REST only).

1. Reserve uploads with each file's name, type and size:

curl -s -X POST "$PP_API/uploads" \
  -H "Authorization: Bearer $PP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"project_id": "'"$PROJECT_ID"'",
       "files": [{"filename": "kitchen.heic", "content_type": "image/heic", "size": 3481234}]}'

The response has an upload id and, per file, an upload_url, the method, the headers to send and a storage_path.

2. Upload each file's bytes to its upload_url with exactly those headers:

curl -s -X PUT "$UPLOAD_URL" -H "Content-Type: image/heic" --data-binary @kitchen.heic

3. Complete the upload, listing every file that uploaded:

curl -s -X POST "$PP_API/uploads/$UPLOAD_ID/complete" \
  -H "Authorization: Bearer $PP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"project_id": "'"$PROJECT_ID"'",
       "files": [{"storage_path": "…", "filename": "kitchen.heic", "size": 3481234, "content_type": "image/heic"}]}'

PropertyPixel checks each file's size, type and contents, then adds it to the project. Files you leave out are discarded. Rejected files are listed in failed with a reason.