PropertyPixel Docs

Quickstart: REST

Enhance a listing from the command line with curl.

This walks through one listing: create a project, add photos by URL, enhance them with a quote, wait for the results, and download them.

1. Create an API key

In PropertyPixel, open Settings → Developers and select Create key. Pick the workspace and choose View and edit access. Copy the key (it starts with pp_live_); it is shown only once.

export PP_API_KEY="pp_live_..."
export PP_API="https://api.propertypixel.app/v1"

Check that it works:

curl -s "$PP_API/account" -H "Authorization: Bearer $PP_API_KEY"

The response shows the workspace, your access level and credits.available.

2. Create a project

curl -s -X POST "$PP_API/projects" \
  -H "Authorization: Bearer $PP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "14 Harbour Street", "address": "14 Harbour Street, Sydney"}'

Note the id in the response:

export PROJECT_ID="..."

3. Add photos by URL

curl -s -X POST "$PP_API/projects/$PROJECT_ID/photos" \
  -H "Authorization: Bearer $PP_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"image_urls": [
        "https://example.com/photos/living-room.jpg",
        "https://example.com/photos/front.jpg"
      ]}'

The response lists the new photos with their IDs, and a failed list for any URL that couldn't be used. To upload files from disk instead, see Uploading photos.

4. Get a quote

Spending operations price the request before running it. Call POST /enhancements without a quote_id:

curl -s -X POST "$PP_API/enhancements" \
  -H "Authorization: Bearer $PP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"project_id": "'"$PROJECT_ID"'", "all_photos": true,
       "enhancement_types": ["improve_lighting", "blue_skies"]}'

Nothing is spent. The response is 409 with code quote_required, and a quote:

{
  "type": "https://docs.propertypixel.app/errors#quote_required",
  "title": "Quote required",
  "status": 409,
  "code": "quote_required",
  "detail": "This request spends credits. Confirm the quote by sending quote_id, or send auto_confirm: true.",
  "quote": {
    "object": "quote",
    "id": "5d1c…",
    "operation": "enhance_photos",
    "credits": 200,
    "balance": { "available": 500, "after": 300 },
    "sufficient": true,
    "watermarked": true,
    "expires_at": "2026-10-04T10:10:00Z"
  }
}

5. Confirm and run

Send the same body again with the quote's id:

curl -s -X POST "$PP_API/enhancements" \
  -H "Authorization: Bearer $PP_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"project_id": "'"$PROJECT_ID"'", "all_photos": true,
       "enhancement_types": ["improve_lighting", "blue_skies"],
       "quote_id": "5d1c…"}'

The response (201) is a job batch: one job per photo, credits_spent, and poll_after_ms.

Scripts that don't need a quote

Send "auto_confirm": true instead of quote_id to spend in one call. Only do this in code you control; see Credits and quotes.

6. Wait for the results

curl -s "$PP_API/jobs?ids=JOB_ID_1,JOB_ID_2" -H "Authorization: Bearer $PP_API_KEY"

Repeat after poll_after_ms until all_done is true. Each completed job has result.url, signed for one hour. Or skip polling and subscribe to the job.completed webhook.

7. Download

One result is a single signed link. Several start a zip:

curl -s -X POST "$PP_API/downloads" \
  -H "Authorization: Bearer $PP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"job_ids": ["JOB_ID_1", "JOB_ID_2"]}'

If status is processing, poll GET /downloads/{id} until it returns a url.

Next