> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fotolabs.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Process a project

> 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.




## OpenAPI

````yaml POST /v1/projects/{projectId}/process
openapi: 3.1.0
info:
  title: Fotolabs API
  version: 1.0.0
  description: >
    Programmatic access to the Fotolabs image processing pipeline.


    **Base URL:** `https://api.fotolabs.co` (prod) ·
    `https://api-staging.fotolabs.co` (staging)


    **Authentication:** Pass your API key as a Bearer token on every request.

    ```

    Authorization: Bearer fl_<key>

    ```


    **Typical flow:**

    1. `POST /v1/projects` — create a project

    2. `POST /v1/images/upload-url` + `PUT <uploadUrl>` — repeat for each image
    (no grouping needed)

    3. `POST /v1/projects/{projectId}/process` — process the whole project in
    one call

    4. `GET /v1/projects/{projectId}` — poll until `status` is `completed`;
    response includes all images and their result URLs


    **Project lifecycle:** `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:**

    - `free` — API access 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.
servers:
  - url: https://api.fotolabs.co
    description: Production
  - url: https://api-staging.fotolabs.co
    description: Staging
security:
  - ApiKeyAuth: []
paths:
  /v1/projects/{projectId}/process:
    post:
      summary: Process all images in a project
      description: >
        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.
      operationId: processProject
      parameters:
        - name: projectId
          in: path
          required: true
          schema:
            type: string
            format: uuid
          example: ca5f09f7-6838-459c-ac0f-7be03c60de24
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                templateId:
                  type: string
                  enum:
                    - original
                    - twilight
                    - virtual-stage
                  default: original
                  description: AI enhancement style. Overrides the project-level default.
                autoLevel:
                  type: boolean
                  default: true
                  description: >-
                    Automatically correct horizon tilt using Hough line
                    detection.
                lensCorrection:
                  type: boolean
                  description: >
                    Override lens distortion correction. Omit to use automatic
                    detection (recommended).

                    `false` skips correction; `true` forces it.
                changeRequestNote:
                  type: string
                  description: >-
                    Free-text instruction passed to the AI model for all images
                    in this batch.
                  example: Brighten the foreground and add a warm sunset tone
                bracketWindowSeconds:
                  type: number
                  minimum: 0.5
                  maximum: 30
                  default: 2
                  description: Time window in seconds used to group HDR bracket exposures.
            example:
              templateId: original
              autoLevel: true
      responses:
        '200':
          description: |
            All jobs enqueued. Project is now in `processing` status.
            Poll each `jobId` via `GET /v1/images/{imageId}`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProcessResponse'
              example:
                jobs:
                  - jobId: aaa-...
                    type: hdr
                    imageIds:
                      - aaa-...
                      - bbb-...
                      - ccc-...
                  - jobId: ddd-...
                    type: hdr
                    imageIds:
                      - ddd-...
                      - eee-...
                  - jobId: fff-...
                    type: single
                    imageIds:
                      - fff-...
                  - jobId: ggg-...
                    type: single
                    imageIds:
                      - ggg-...
        '400':
          description: No pending images found, or validation error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                noPendingImages:
                  value:
                    error: >-
                      No pending images found for this project. Upload images
                      first.
                badTemplate:
                  value:
                    error: >-
                      Invalid templateId. Allowed: original, twilight,
                      virtual-stage
                badWindow:
                  value:
                    error: bracketWindowSeconds must be between 0.5 and 30
        '401':
          description: Invalid or missing API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '402':
          description: Payment required or card failed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                noPaymentMethod:
                  summary: No card on file
                  value:
                    error: >-
                      No payment method on file. Please add one at fotolabs.co
                      before processing images.
                cardDeclined:
                  summary: Card declined
                  value:
                    error: Your card was declined.
                requires3ds:
                  summary: 3DS authentication required
                  value:
                    error: >-
                      Your card requires additional authentication. Please
                      complete payment at fotolabs.co before using the API.
                quotaExceededNoCard:
                  summary: Monthly quota exhausted, no fallback card
                  value:
                    error: >-
                      Monthly quota exceeded and no payment method on file.
                      Please update billing at fotolabs.co
        '403':
          description: Free plan workspace or project belongs to a different workspace.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                freePlan:
                  value:
                    error: >-
                      API access requires an Essential or Ultimate plan. Upgrade
                      at fotolabs.co
                wrongWorkspace:
                  value:
                    error: Project not found or access denied
        '404':
          description: Project not found.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Project not found or access denied
        '409':
          description: Project is not in `pending` status — processing is locked.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                alreadyProcessing:
                  summary: Already in progress
                  value:
                    error: Project is already processing.
                alreadyCompleted:
                  summary: Already done
                  value:
                    error: >-
                      Project has already been processed. Create a new project
                      to process more images.
components:
  schemas:
    ProcessResponse:
      type: object
      required:
        - jobs
      properties:
        jobs:
          type: array
          items:
            $ref: '#/components/schemas/Job'
    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: string
          example: >-
            No payment method on file. Please add one at fotolabs.co before
            processing images.
    Job:
      type: object
      required:
        - jobId
        - type
        - imageIds
      properties:
        jobId:
          type: string
          format: uuid
          description: The primary imageId for this job. Use this to poll status.
        type:
          type: string
          enum:
            - single
            - hdr
          description: >-
            `single` for a standalone image; `hdr` for an auto-detected HDR
            bracket set.
        imageIds:
          type: array
          items:
            type: string
            format: uuid
          description: >-
            All imageIds in this job. HDR jobs have multiple; single jobs have
            one.
  securitySchemes:
    ApiKeyAuth:
      type: http
      scheme: bearer
      description: API key with `fl_` prefix, issued from the Fotolabs dashboard

````