# Create a project Source: https://docs.fotolabs.co/api-reference/endpoint/create-project POST /v1/projects Creates a new project (listing). Returns a `projectId` to use in subsequent upload and process calls. New projects start in `pending` status. # Get image status Source: https://docs.fotolabs.co/api-reference/endpoint/get-image GET /v1/images/{imageId} Poll this endpoint after calling `POST /v1/projects/{projectId}/process`. Use the `jobId` values from the process response. Processing typically completes in **60–120 seconds** per job. HDR merge jobs may take slightly longer. For HDR jobs, `resultImageUrl` is populated only on the primary image (`jobId`). The other bracket members in the group will have `status: completed` but no `resultImageUrl`. # Get project status Source: https://docs.fotolabs.co/api-reference/endpoint/get-project GET /v1/projects/{projectId} Poll this after calling `POST /v1/projects/{projectId}/process`. Returns the project status and the current state of every image in the project. The project moves to `completed` once all jobs finish. **Polling tip:** check `project.status` — when it's `completed` all images are done. Individual images may still be `processing` while `project.status` is `processing`. # Get a presigned upload URL Source: https://docs.fotolabs.co/api-reference/endpoint/get-upload-url POST /v1/images/upload-url Creates a pending image record and returns a presigned S3 PUT URL. **Supported formats:** JPEG, PNG, and RAW files — NEF, CR2, CR3, ARW, DNG, ORF, RW2, RAF, PEF, MRW, SRW, RAW. After receiving the URL, upload the file directly to S3 with a `PUT` request using the matching `Content-Type` header. No auth header is needed on the S3 upload. The pipeline (RAW vs JPEG) is chosen automatically from the file extension. **Project must be in `pending` status.** Uploads are blocked once processing has started or completed. # Process a project Source: https://docs.fotolabs.co/api-reference/endpoint/process-project POST /v1/projects/{projectId}/process Fetches all `pending` images for the project, auto-detects HDR bracket sets from EXIF metadata, groups them, and enqueues all jobs in a single call. **Project must be in `pending` status.** Returns 409 if already processing or completed. Once this call succeeds, the project moves to `processing` status — no further uploads are accepted and this endpoint cannot be called again for the same project. **HDR detection:** Images captured within `bracketWindowSeconds` of each other with an EV spread ≥ 0.5 stops are automatically grouped as HDR bracket sets. No client-side grouping is needed — upload all images flat and let the API handle it. **Payment:** Charged once per project. - PAYG plans (`essential` / `ultimate`): charged at the plan rate from your pricing tier. - Monthly plans: deducts one listing from your quota; if exhausted, the overage rate is charged. - Second call on the same project (after adding more images): free — project is already paid. # API reference Source: https://docs.fotolabs.co/api-reference/introduction Programmatic access to the Fotolabs image processing pipeline ## Base URLs | Environment | URL | | ----------- | ------------------------- | | Production | `https://api.fotolabs.co` | ## Authentication All endpoints require an API key passed as a Bearer token. ```http theme={null} Authorization: Bearer fl_ ``` Get your API key from the [Fotolabs dashboard](https://fotolabs.co). ## Typical flow `POST /v1/projects` — create a project for a listing. `POST /v1/images/upload-url` for each file → `PUT ` directly to S3. Repeat for every image; no client-side grouping needed. `POST /v1/projects/{projectId}/process` — enqueues all jobs in one call. HDR bracket sets are detected automatically from EXIF metadata. `GET /v1/projects/{projectId}` — check `status`. When it's `completed`, all `resultImageUrl` values are ready. ## Project lifecycle Projects move through `pending` → `processing` → `completed`. * Images can only be uploaded to a **`pending`** project. * Processing can only be triggered on a **`pending`** project. * Once processing starts the project is locked — create a new project for additional images. ## Plans | Plan | API access | | ---------------------------------------- | --------------------------------------------------------------------------------------- | | `free` | Blocked | | `essential` / `ultimate` (PAYG) | Charged once per project at the plan rate | | `essential_monthly` / `ultimate_monthly` | Deducts one listing from your monthly quota; overage rate applies if quota is exhausted | ## HDR bracket detection Upload all bracket exposures flat — no grouping needed on the client. When you call `POST /v1/projects/{projectId}/process`, images captured within `bracketWindowSeconds` of each other with an EV spread ≥ 0.5 stops are automatically grouped as HDR bracket sets. ## Processing time Each job typically completes in **60–120 seconds**. HDR merge jobs may take slightly longer. # Fotolabs API Source: https://docs.fotolabs.co/index AI-powered real estate photo enhancement and video generation ## What you can build Use the Fotolabs API to plug AI photo enhancement into your own workflow — MLS integrations, photography apps, batch processing pipelines, and more. Upload and process your first batch of photos in minutes. Full reference for all endpoints, parameters, and responses. ## How it works One project per listing. Pass a name (address works great) and an enhancement style. Get a presigned S3 URL for each photo and upload directly — JPEG, PNG, or RAW (NEF, CR2, ARW, DNG, and more). One API call triggers the entire batch. HDR brackets are auto-detected from EXIF — no grouping needed on your end. Poll the project endpoint until `status` is `completed`. Each image returns a CDN URL with the processed result. ## Enhancement styles | `templateId` | Description | | --------------- | -------------------------------------------------------------------------------------- | | `original` | Signature enhancement — shadow lift, highlight pull, lens correction, horizon leveling | | `twilight` | Day-to-dusk conversion with warm window glow | | `virtual-stage` | Adds contemporary Scandinavian furniture to empty rooms | # Quickstart Source: https://docs.fotolabs.co/quickstart Upload and process your first listing in minutes ## Prerequisites * A Fotolabs account on an Essential or Ultimate plan * Your API key from the [Fotolabs dashboard](https://fotolabs.co) ## 1. Create a project ```bash theme={null} curl -X POST https://api.fotolabs.co/v1/projects \ -H "Authorization: Bearer fl_" \ -H "Content-Type: application/json" \ -d '{ "name": "233 Broadway, New York, NY", "templateId": "original" }' ``` ```json theme={null} { "projectId": "ca5f09f7-6838-459c-ac0f-7be03c60de24", "name": "233 Broadway, New York, NY" } ``` Save the `projectId` — you'll use it in every subsequent call. ## 2. Upload images Call this once per image. Supported formats: JPEG, PNG, NEF, CR2, CR3, ARW, DNG, ORF, RW2, RAF, and more. ```bash theme={null} curl -X POST https://api.fotolabs.co/v1/images/upload-url \ -H "Authorization: Bearer fl_" \ -H "Content-Type: application/json" \ -d '{ "filename": "Z6A_0235.NEF", "projectId": "ca5f09f7-..." }' ``` ```json theme={null} { "imageId": "f3e088d1-33a5-4227-a2f6-c4f75617f847", "uploadUrl": "https://fotolabs-images-prod.s3.amazonaws.com/...", "originalImageUrl": "https://cdn.fotolabs.co/...", "expiresAt": "2026-05-09T20:00:00.000Z" } ``` Then PUT the file directly to S3 — no auth header needed: ```bash theme={null} curl -X PUT "" \ -H "Content-Type: image/x-nikon-nef" \ --data-binary @Z6A_0235.NEF ``` Repeat for every photo in the listing. ## 3. Process the project One call enqueues all images. HDR brackets are detected automatically from EXIF timestamps and exposure values — just upload everything flat. ```bash theme={null} curl -X POST https://api.fotolabs.co/v1/projects/ca5f09f7-.../process \ -H "Authorization: Bearer fl_" \ -H "Content-Type: application/json" \ -d '{ "templateId": "original", "autoLevel": true }' ``` ```json theme={null} { "jobs": [ { "jobId": "aaa-...", "type": "hdr", "imageIds": ["aaa-...", "bbb-...", "ccc-..."] }, { "jobId": "ddd-...", "type": "single", "imageIds": ["ddd-..."] } ] } ``` ## 4. Poll for results Processing takes **60–120 seconds** per job. Poll the project until `status` is `completed`. ```bash theme={null} curl https://api.fotolabs.co/v1/projects/ca5f09f7-... \ -H "Authorization: Bearer fl_" ``` ```json theme={null} { "projectId": "ca5f09f7-...", "status": "completed", "images": [ { "imageId": "aaa-...", "status": "completed", "resultImageUrl": "https://cdn.fotolabs.co/.../result/aaa-....jpg", "originalImageUrl": "https://cdn.fotolabs.co/...", "errorMessage": null, "createdAt": "2026-05-09T18:00:48.421Z", "updatedAt": "2026-05-09T18:06:00.240Z" } ] } ``` Download each `resultImageUrl` — that's your processed JPEG. ## Next steps Full parameter reference and error codes. Twilight, virtual staging, and custom change request notes.