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

> ## Agent Instructions
> The base URL is https://api.sudomock.com.
> Authenticate every request with the x-api-key header. Keys begin with sm_.
> A render returns the finished image at data.print_files[0].export_path. A request sent with is_async true returns a job_id to poll at GET /api/v1/jobs/{job_id}.
> Prefer the official SDKs over hand-written HTTP calls: npm install sudomock for Node, pip install sudomock for Python.

# Render a photo mockup

> Renders artwork onto a previously created photo mockup identified by the path mockup_id. Artwork can target a saved print area or a whole product surface, and a product offers both. The mockup must be in 'ready' status. Costs 5 credits. Returns CDN URL(s) of the rendered image.

<RequestExample>
  ```js Node.js theme={"theme":{"light":"github-light","dark":"vesper"}}
  const response = await fetch("https://api.sudomock.com/api/v1/photo-mockups/3fa85f64-5717-4562-b3fc-2c963f66afa6/render", {
    method: "POST",
    headers: {
      "x-api-key": "sm_your_api_key",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      "export_options": {
        "image_format": "webp",
        "image_size": 1920,
        "quality": 95
      },
      "print_areas": [
        {
          "adjustments": {
            "blend_mode": "multiply",
            "opacity": 90
          },
          "artwork_url": "https://example.com/design.png",
          "placement": {
            "fit": "fit",
            "position": "center"
          },
          "uuid": "223e4567-e89b-12d3-a456-426614174001"
        }
      ]
    }),
  });

  const data = await response.json();
  console.log(data);
  ```

  ```php PHP theme={"theme":{"light":"github-light","dark":"vesper"}}
  <?php

  $payload = <<<'JSON'
  {
    "export_options": {
      "image_format": "webp",
      "image_size": 1920,
      "quality": 95
    },
    "print_areas": [
      {
        "adjustments": {
          "blend_mode": "multiply",
          "opacity": 90
        },
        "artwork_url": "https://example.com/design.png",
        "placement": {
          "fit": "fit",
          "position": "center"
        },
        "uuid": "223e4567-e89b-12d3-a456-426614174001"
      }
    ]
  }
  JSON;

  $ch = curl_init("https://api.sudomock.com/api/v1/photo-mockups/3fa85f64-5717-4562-b3fc-2c963f66afa6/render");
  curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($ch, CURLOPT_HTTPHEADER, [
      "x-api-key: sm_your_api_key",
      "Content-Type: application/json",
  ]);
  curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);

  $response = curl_exec($ch);
  curl_close($ch);

  echo $response;
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"vesper"}}
  import requests

  payload = {
      "export_options": {
          "image_format": "webp",
          "image_size": 1920,
          "quality": 95
      },
      "print_areas": [
          {
              "adjustments": {
                  "blend_mode": "multiply",
                  "opacity": 90
              },
              "artwork_url": "https://example.com/design.png",
              "placement": {
                  "fit": "fit",
                  "position": "center"
              },
              "uuid": "223e4567-e89b-12d3-a456-426614174001"
          }
      ]
  }

  response = requests.post(
      "https://api.sudomock.com/api/v1/photo-mockups/3fa85f64-5717-4562-b3fc-2c963f66afa6/render",
      headers={"x-api-key": "sm_your_api_key"},
      json=payload,
  )

  response.raise_for_status()
  print(response.json())
  ```

  ```ruby Ruby theme={"theme":{"light":"github-light","dark":"vesper"}}
  require "net/http"
  require "uri"

  uri = URI("https://api.sudomock.com/api/v1/photo-mockups/3fa85f64-5717-4562-b3fc-2c963f66afa6/render")
  request = Net::HTTP::Post.new(uri)
  request["x-api-key"] = "sm_your_api_key"
  request["Content-Type"] = "application/json"

  request.body = <<~JSON
    {
      "export_options": {
        "image_format": "webp",
        "image_size": 1920,
        "quality": 95
      },
      "print_areas": [
        {
          "adjustments": {
            "blend_mode": "multiply",
            "opacity": 90
          },
          "artwork_url": "https://example.com/design.png",
          "placement": {
            "fit": "fit",
            "position": "center"
          },
          "uuid": "223e4567-e89b-12d3-a456-426614174001"
        }
      ]
    }
  JSON

  response = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
    http.request(request)
  end

  puts response.body
  ```

  ```go Go theme={"theme":{"light":"github-light","dark":"vesper"}}
  package main

  import (
  	"bytes"
  	"fmt"
  	"io"
  	"net/http"
  )

  func main() {
  	payload := []byte(`{
    "export_options": {
      "image_format": "webp",
      "image_size": 1920,
      "quality": 95
    },
    "print_areas": [
      {
        "adjustments": {
          "blend_mode": "multiply",
          "opacity": 90
        },
        "artwork_url": "https://example.com/design.png",
        "placement": {
          "fit": "fit",
          "position": "center"
        },
        "uuid": "223e4567-e89b-12d3-a456-426614174001"
      }
    ]
  }`)

  	req, err := http.NewRequest("POST", "https://api.sudomock.com/api/v1/photo-mockups/3fa85f64-5717-4562-b3fc-2c963f66afa6/render", bytes.NewBuffer(payload))
  	if err != nil {
  		panic(err)
  	}
  	req.Header.Set("x-api-key", "sm_your_api_key")
  	req.Header.Set("Content-Type", "application/json")

  	res, err := http.DefaultClient.Do(req)
  	if err != nil {
  		panic(err)
  	}
  	defer res.Body.Close()

  	body, _ := io.ReadAll(res.Body)
  	fmt.Println(string(body))
  }
  ```

  ```java Java theme={"theme":{"light":"github-light","dark":"vesper"}}
  import java.net.URI;
  import java.net.http.HttpClient;
  import java.net.http.HttpRequest;
  import java.net.http.HttpResponse;

  String payload = """
  {
    "export_options": {
      "image_format": "webp",
      "image_size": 1920,
      "quality": 95
    },
    "print_areas": [
      {
        "adjustments": {
          "blend_mode": "multiply",
          "opacity": 90
        },
        "artwork_url": "https://example.com/design.png",
        "placement": {
          "fit": "fit",
          "position": "center"
        },
        "uuid": "223e4567-e89b-12d3-a456-426614174001"
      }
    ]
  }
  """;

  HttpRequest request = HttpRequest.newBuilder()
      .uri(URI.create("https://api.sudomock.com/api/v1/photo-mockups/3fa85f64-5717-4562-b3fc-2c963f66afa6/render"))
      .header("x-api-key", "sm_your_api_key")
      .header("Content-Type", "application/json")
      .POST(HttpRequest.BodyPublishers.ofString(payload))
      .build();

  HttpResponse<String> response = HttpClient.newHttpClient()
      .send(request, HttpResponse.BodyHandlers.ofString());

  System.out.println(response.body());
  ```

  ```csharp .NET theme={"theme":{"light":"github-light","dark":"vesper"}}
  using System.Net.Http;
  using System.Text;

  var payload = """
  {
    "export_options": {
      "image_format": "webp",
      "image_size": 1920,
      "quality": 95
    },
    "print_areas": [
      {
        "adjustments": {
          "blend_mode": "multiply",
          "opacity": 90
        },
        "artwork_url": "https://example.com/design.png",
        "placement": {
          "fit": "fit",
          "position": "center"
        },
        "uuid": "223e4567-e89b-12d3-a456-426614174001"
      }
    ]
  }
  """;

  var request = new HttpRequestMessage(HttpMethod.Post, "https://api.sudomock.com/api/v1/photo-mockups/3fa85f64-5717-4562-b3fc-2c963f66afa6/render");
  request.Headers.Add("x-api-key", "sm_your_api_key");
  request.Content = new StringContent(payload, Encoding.UTF8, "application/json");

  var client = new HttpClient();
  var response = await client.SendAsync(request);

  Console.WriteLine(await response.Content.ReadAsStringAsync());
  ```

  ```bash cURL theme={"theme":{"light":"github-light","dark":"vesper"}}
  curl -X POST "https://api.sudomock.com/api/v1/photo-mockups/3fa85f64-5717-4562-b3fc-2c963f66afa6/render" \
    -H "x-api-key: sm_your_api_key" \
    -H "Content-Type: application/json" \
    -d '{
      "export_options": {
        "image_format": "webp",
        "image_size": 1920,
        "quality": 95
      },
      "print_areas": [
        {
          "adjustments": {
            "blend_mode": "multiply",
            "opacity": 90
          },
          "artwork_url": "https://example.com/design.png",
          "placement": {
            "fit": "fit",
            "position": "center"
          },
          "uuid": "223e4567-e89b-12d3-a456-426614174001"
        }
      ]
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json Response theme={"theme":{"light":"github-light","dark":"vesper"}}
  {
    "data": {
      "print_files": [
        {
          "export_path": "string"
        }
      ]
    }
  }
  ```
</ResponseExample>


## OpenAPI

````yaml openapi.json POST /api/v1/photo-mockups/{mockup_id}/render
openapi: 3.1.0
info:
  title: SudoMock API
  description: >-
    Product mockup API. Render PSD templates, turn product photos into reusable
    mockups, create still images and videos, personalize text with fonts, and
    manage asynchronous jobs and signed webhooks.


    Every endpoint answers failures with the same envelope, so the status codes,
    the error_code values and the retry rule are documented once at
    https://sudomock.com/docs/errors rather than repeated per operation.
  version: 1.0.0
servers:
  - url: https://api.sudomock.com
    description: Production
security: []
tags:
  - name: PSD mockups
    description: Turn a Photoshop file into a reusable mockup, then render it.
  - name: Photo mockups
    description: Turn a product photo into a reusable mockup, then render artwork onto it.
  - name: Video mockups
    description: Render a mockup as a short video.
  - name: Fonts
    description: Upload and manage the fonts available to text layers.
  - name: Background removal
    description: Isolate a subject from its background as a standalone step.
  - name: Studio
    description: Open an embedded editor session and read what the customer produced in it.
  - name: Webhook endpoints
    description: Register signed endpoints and manage their secrets.
  - name: Webhook deliveries
    description: Inspect, replay and retry what those endpoints received.
  - name: Jobs
    description: Poll queued renders and read their results.
  - name: Account
    description: Read the current account, its plan and its remaining credits.
paths:
  /api/v1/photo-mockups/{mockup_id}/render:
    post:
      tags:
        - Photo mockups
      summary: Render a photo mockup
      description: >-
        Renders artwork onto a previously created photo mockup identified by the
        path mockup_id. Artwork can target a saved print area or a whole product
        surface, and a product offers both. The mockup must be in 'ready'
        status. Costs 5 credits. Returns CDN URL(s) of the rendered image.
      operationId: render_2d_mockup_public_api_v1_photo_mockups__mockup_id__render_post
      parameters:
        - name: mockup_id
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PhotoMockupRender'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PhotoMockupRenderResponse'
        '202':
          description: >-
            Render queued (is_async=true): returns a job envelope with job_id +
            status_url to poll (or a webhook on completion).
      security:
        - ApiKeyAuth: []
      x-codeSamples:
        - lang: Node.js
          source: >-
            const response = await
            fetch("https://api.sudomock.com/api/v1/photo-mockups/3fa85f64-5717-4562-b3fc-2c963f66afa6/render",
            {
              method: "POST",
              headers: {
                "x-api-key": "sm_your_api_key",
                "Content-Type": "application/json",
              },
              body: JSON.stringify({
                "export_options": {
                  "image_format": "webp",
                  "image_size": 1920,
                  "quality": 95
                },
                "print_areas": [
                  {
                    "adjustments": {
                      "blend_mode": "multiply",
                      "opacity": 90
                    },
                    "artwork_url": "https://example.com/design.png",
                    "placement": {
                      "fit": "fit",
                      "position": "center"
                    },
                    "uuid": "223e4567-e89b-12d3-a456-426614174001"
                  }
                ]
              }),
            });


            const data = await response.json();

            console.log(data);
        - lang: PHP
          source: >-
            <?php


            $payload = <<<'JSON'

            {
              "export_options": {
                "image_format": "webp",
                "image_size": 1920,
                "quality": 95
              },
              "print_areas": [
                {
                  "adjustments": {
                    "blend_mode": "multiply",
                    "opacity": 90
                  },
                  "artwork_url": "https://example.com/design.png",
                  "placement": {
                    "fit": "fit",
                    "position": "center"
                  },
                  "uuid": "223e4567-e89b-12d3-a456-426614174001"
                }
              ]
            }

            JSON;


            $ch =
            curl_init("https://api.sudomock.com/api/v1/photo-mockups/3fa85f64-5717-4562-b3fc-2c963f66afa6/render");

            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");

            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

            curl_setopt($ch, CURLOPT_HTTPHEADER, [
                "x-api-key: sm_your_api_key",
                "Content-Type: application/json",
            ]);

            curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);


            $response = curl_exec($ch);

            curl_close($ch);


            echo $response;
        - lang: Python
          source: |-
            import requests

            payload = {
                "export_options": {
                    "image_format": "webp",
                    "image_size": 1920,
                    "quality": 95
                },
                "print_areas": [
                    {
                        "adjustments": {
                            "blend_mode": "multiply",
                            "opacity": 90
                        },
                        "artwork_url": "https://example.com/design.png",
                        "placement": {
                            "fit": "fit",
                            "position": "center"
                        },
                        "uuid": "223e4567-e89b-12d3-a456-426614174001"
                    }
                ]
            }

            response = requests.post(
                "https://api.sudomock.com/api/v1/photo-mockups/3fa85f64-5717-4562-b3fc-2c963f66afa6/render",
                headers={"x-api-key": "sm_your_api_key"},
                json=payload,
            )

            response.raise_for_status()
            print(response.json())
        - lang: Ruby
          source: >-
            require "net/http"

            require "uri"


            uri =
            URI("https://api.sudomock.com/api/v1/photo-mockups/3fa85f64-5717-4562-b3fc-2c963f66afa6/render")

            request = Net::HTTP::Post.new(uri)

            request["x-api-key"] = "sm_your_api_key"

            request["Content-Type"] = "application/json"


            request.body = <<~JSON
              {
                "export_options": {
                  "image_format": "webp",
                  "image_size": 1920,
                  "quality": 95
                },
                "print_areas": [
                  {
                    "adjustments": {
                      "blend_mode": "multiply",
                      "opacity": 90
                    },
                    "artwork_url": "https://example.com/design.png",
                    "placement": {
                      "fit": "fit",
                      "position": "center"
                    },
                    "uuid": "223e4567-e89b-12d3-a456-426614174001"
                  }
                ]
              }
            JSON


            response = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do
            |http|
              http.request(request)
            end


            puts response.body
        - lang: Go
          source: "package main\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n)\n\nfunc main() {\n\tpayload := []byte(`{\n  \"export_options\": {\n    \"image_format\": \"webp\",\n    \"image_size\": 1920,\n    \"quality\": 95\n  },\n  \"print_areas\": [\n    {\n      \"adjustments\": {\n        \"blend_mode\": \"multiply\",\n        \"opacity\": 90\n      },\n      \"artwork_url\": \"https://example.com/design.png\",\n      \"placement\": {\n        \"fit\": \"fit\",\n        \"position\": \"center\"\n      },\n      \"uuid\": \"223e4567-e89b-12d3-a456-426614174001\"\n    }\n  ]\n}`)\n\n\treq, err := http.NewRequest(\"POST\", \"https://api.sudomock.com/api/v1/photo-mockups/3fa85f64-5717-4562-b3fc-2c963f66afa6/render\", bytes.NewBuffer(payload))\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treq.Header.Set(\"x-api-key\", \"sm_your_api_key\")\n\treq.Header.Set(\"Content-Type\", \"application/json\")\n\n\tres, err := http.DefaultClient.Do(req)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer res.Body.Close()\n\n\tbody, _ := io.ReadAll(res.Body)\n\tfmt.Println(string(body))\n}"
        - lang: Java
          source: |-
            import java.net.URI;
            import java.net.http.HttpClient;
            import java.net.http.HttpRequest;
            import java.net.http.HttpResponse;

            String payload = """
            {
              "export_options": {
                "image_format": "webp",
                "image_size": 1920,
                "quality": 95
              },
              "print_areas": [
                {
                  "adjustments": {
                    "blend_mode": "multiply",
                    "opacity": 90
                  },
                  "artwork_url": "https://example.com/design.png",
                  "placement": {
                    "fit": "fit",
                    "position": "center"
                  },
                  "uuid": "223e4567-e89b-12d3-a456-426614174001"
                }
              ]
            }
            """;

            HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://api.sudomock.com/api/v1/photo-mockups/3fa85f64-5717-4562-b3fc-2c963f66afa6/render"))
                .header("x-api-key", "sm_your_api_key")
                .header("Content-Type", "application/json")
                .POST(HttpRequest.BodyPublishers.ofString(payload))
                .build();

            HttpResponse<String> response = HttpClient.newHttpClient()
                .send(request, HttpResponse.BodyHandlers.ofString());

            System.out.println(response.body());
        - lang: .NET
          source: >-
            using System.Net.Http;

            using System.Text;


            var payload = """

            {
              "export_options": {
                "image_format": "webp",
                "image_size": 1920,
                "quality": 95
              },
              "print_areas": [
                {
                  "adjustments": {
                    "blend_mode": "multiply",
                    "opacity": 90
                  },
                  "artwork_url": "https://example.com/design.png",
                  "placement": {
                    "fit": "fit",
                    "position": "center"
                  },
                  "uuid": "223e4567-e89b-12d3-a456-426614174001"
                }
              ]
            }

            """;


            var request = new HttpRequestMessage(HttpMethod.Post,
            "https://api.sudomock.com/api/v1/photo-mockups/3fa85f64-5717-4562-b3fc-2c963f66afa6/render");

            request.Headers.Add("x-api-key", "sm_your_api_key");

            request.Content = new StringContent(payload, Encoding.UTF8,
            "application/json");


            var client = new HttpClient();

            var response = await client.SendAsync(request);


            Console.WriteLine(await response.Content.ReadAsStringAsync());
        - lang: cURL
          source: >-
            curl -X POST
            "https://api.sudomock.com/api/v1/photo-mockups/3fa85f64-5717-4562-b3fc-2c963f66afa6/render"
            \
              -H "x-api-key: sm_your_api_key" \
              -H "Content-Type: application/json" \
              -d '{
                "export_options": {
                  "image_format": "webp",
                  "image_size": 1920,
                  "quality": 95
                },
                "print_areas": [
                  {
                    "adjustments": {
                      "blend_mode": "multiply",
                      "opacity": 90
                    },
                    "artwork_url": "https://example.com/design.png",
                    "placement": {
                      "fit": "fit",
                      "position": "center"
                    },
                    "uuid": "223e4567-e89b-12d3-a456-426614174001"
                  }
                ]
              }'
components:
  schemas:
    PhotoMockupRender:
      properties:
        print_areas:
          items:
            $ref: '#/components/schemas/PhotoMockupPrintAreaRender'
          type: array
          maxItems: 8
          minItems: 1
          description: >-
            Artwork configuration per render target. Use uuid for a saved print
            area, and surface_uuid for a whole product surface. A product can be
            rendered either way, and saving a print area on it does not take its
            surface away.
        export_options:
          $ref: '#/components/schemas/ExportOptions'
          description: >-
            Export configuration for format, size and quality. Every field has a
            default, so the whole object is optional.
        is_async:
          type: boolean
          description: >-
            If true, the render is QUEUED and the call returns 202 immediately
            with a job_id (poll GET /api/v1/jobs/{job_id}, or receive a webhook
            if one is configured); result_url carries the rendered image URL on
            success. If false (default), the render runs synchronously and
            returns the result.
          default: false
      additionalProperties: false
      type: object
      required:
        - print_areas
      title: PhotoMockupRender
      description: >-
        Body for POST /api/v1/photo-mockups/{mockup_id}/render.


        The mockup UUID is taken from the path; the body carries only
        per-print-area

        artwork configuration and export options.
      example:
        export_options:
          image_format: webp
          image_size: 1920
          quality: 95
        print_areas:
          - adjustments:
              blend_mode: multiply
              opacity: 90
            artwork_url: https://example.com/design.png
            placement:
              fit: fit
              position: center
            uuid: 223e4567-e89b-12d3-a456-426614174001
    PhotoMockupRenderResponse:
      properties:
        data:
          $ref: '#/components/schemas/PhotoMockupRenderResult'
          description: Rendered output files
        success:
          type: boolean
          description: Success status
          default: true
      type: object
      required:
        - data
      title: PhotoMockupRenderResponse
      description: The finished photo-mockup render and where to fetch it.
    PhotoMockupPrintAreaRender:
      properties:
        uuid:
          anyOf:
            - type: string
              pattern: ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$
            - type: 'null'
          description: UUID of a saved print area, a bounded zone drawn on a product.
          examples:
            - 19be48d4-c810-4420-86e3-7ec2a4d85571
        surface_uuid:
          anyOf:
            - type: string
              pattern: ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$
            - type: 'null'
          description: >-
            UUID of a printable product surface. A product carrying saved print
            areas still has one, and it is a separate render target from them.
          examples:
            - 733ee99a-f41f-4b9b-bf33-2ffa489f96db
        base64:
          anyOf:
            - type: string
            - type: 'null'
          description: Base64-encoded artwork image.
        artwork_url:
          anyOf:
            - type: string
            - type: 'null'
          description: Artwork image URL
          examples:
            - https://example.com/design.png
        color:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            Solid color as a hex code (e.g., '#FF0000'), or the name of a colour
            saved on this mockup (e.g., 'blue jean'). Names match exactly and
            are set with PATCH /api/v1/photo-mockups/{uuid}.
          examples:
            - '#6A8296'
        adjustments:
          anyOf:
            - $ref: '#/components/schemas/PhotoMockupAdjustments'
            - type: 'null'
          description: Optional visual adjustments for the artwork.
        placement:
          anyOf:
            - $ref: '#/components/schemas/PhotoMockupPlacement'
            - type: 'null'
          description: >-
            Where the artwork sits and how big it is. position, offset_x,
            offset_y and rotation apply to either target. Sizing follows the
            target: coverage on a surface_uuid target, and either fit or an
            explicit width and height on a uuid target.
        flip_horizontal:
          type: boolean
          description: Flip artwork horizontally (left-right mirror)
          default: false
        flip_vertical:
          type: boolean
          description: Flip artwork vertically (top-bottom mirror)
          default: false
        remove_background:
          type: boolean
          description: >-
            Remove the image background before placing the artwork; the subject
            is isolated onto a clean transparent cutout. Adds 25 credits per
            artwork to the render cost.
          default: false
      additionalProperties: false
      type: object
      title: PhotoMockupPrintAreaRender
      description: |-
        Per-print-area artwork configuration for 2D render.
        Mirrors SmartObjectInput pattern from PSD render endpoint.
    ExportOptions:
      properties:
        image_format:
          type: string
          enum:
            - png
            - jpg
            - webp
          description: >-
            Output format: 'webp' (30-70% smaller, recommended), 'png'
            (lossless), 'jpg' (smallest, no transparency)
          default: webp
        image_size:
          type: integer
          maximum: 10000
          minimum: 100
          description: >-
            Output width in pixels (100-10000). Height auto-calculated from the
            source aspect ratio. Powers of 2 (1024, 2048, 4096) recommended for
            best quality. Renders on an account in trial are capped at 1024: a
            larger image_size is rejected with error_code
            OUTPUT_RESOLUTION_LIMIT (HTTP 402) and is never silently downscaled.
            Add a payment method to render at full width.
          default: 2048
        quality:
          type: integer
          maximum: 100
          minimum: 1
          description: >-
            Compression quality for JPG/WebP (1-100). Ignored for PNG (always
            lossless). Default: 90.
          default: 90
        dpi:
          anyOf:
            - type: integer
              maximum: 2400
              minimum: 72
            - type: 'null'
          description: >-
            Resolution tag stamped into the output file metadata (JPG/WebP via
            Exif XResolution, PNG via pHYs), e.g. 300 for print. This is
            metadata only: it does NOT change the pixels. Pixel dimensions are
            controlled by image_size: set image_size = print_size_inches * dpi
            for a true print-ready file (e.g. 12 in * 300 = 3600 px). Range
            72-2400. Default: null (opt-in). Omitting it does not leave the file
            untagged: the encoder writes a default ~25.4 DPI (1 px/mm) tag. All
            three formats carry the tag, but for maximum print-tool
            compatibility prefer jpg or png, because WebP stores resolution in
            Exif and not every viewer surfaces it.
          examples:
            - 300
      type: object
      title: ExportOptions
      description: Format, size and quality of the rendered file.
      example:
        image_format: webp
        image_size: 2048
        quality: 95
    PhotoMockupRenderResult:
      properties:
        print_files:
          items:
            $ref: '#/components/schemas/PhotoMockupPrintFile'
          type: array
          description: List of rendered outputs
        render_uuid:
          anyOf:
            - type: string
            - type: 'null'
          description: Identifier for this render.
      type: object
      required:
        - print_files
      title: PhotoMockupRenderResult
      description: Data payload in SudoAI render response
    PhotoMockupAdjustments:
      properties:
        brightness:
          type: integer
          maximum: 150
          minimum: -150
          default: 0
        contrast:
          type: integer
          maximum: 100
          minimum: -100
          default: 0
        opacity:
          type: integer
          maximum: 100
          minimum: 0
          default: 100
        saturation:
          type: integer
          maximum: 100
          minimum: -100
          default: 0
        vibrance:
          type: integer
          maximum: 100
          minimum: -100
          default: 0
        blur:
          type: integer
          maximum: 100
          minimum: 0
          default: 0
        blend_mode:
          type: string
          enum:
            - multiply
            - normal
            - screen
            - lighten
            - soft_light
            - overlay
            - darken
          description: >-
            How the artwork sits on the product surface. 'multiply' keeps the
            material texture visible and is the best choice on light fabric
            (default); 'normal' reproduces the artwork colors exactly, whatever
            the product color, and is the right choice when a brand color has to
            match the supplied file; 'screen' lightens the artwork against the
            surface, which is worth reaching for only when you want that lighter
            result, since the default already adapts to a dark garment;
            'lighten' keeps the artwork only where it is brighter than the
            surface; 'soft_light' gives a subtle, low-contrast finish that
            follows the surface; 'overlay' deepens contrast so the artwork reads
            as part of the material; 'darken' keeps the artwork only where it is
            darker than the surface.
          default: multiply
      additionalProperties: false
      type: object
      title: PhotoMockupAdjustments
      description: Outcome-level controls for the public 2D render API.
    PhotoMockupPlacement:
      properties:
        position:
          type: string
          enum:
            - center
            - top_left
            - top_center
            - top_right
            - center_left
            - center_right
            - left_center
            - right_center
            - bottom_left
            - bottom_center
            - bottom_right
          description: Predefined position within print area
          default: center
        coverage:
          anyOf:
            - type: integer
              maximum: 100
              minimum: 10
            - type: 'null'
          description: >-
            How much of the product surface the artwork spans, 10 to 100. Spans
            the whole surface by default. Belongs to a surface_uuid target, and
            cannot be combined with an explicit width and height.
        fit:
          anyOf:
            - type: string
              enum:
                - fill
                - fit
                - crop
            - type: 'null'
          description: >-
            How the artwork meets the print area. 'fit' scales it until it fits
            inside and keeps its proportions, which is the default and can leave
            empty space. 'fill' stretches it to the edges and does not keep
            proportions. 'crop' covers the area and cuts the overflow, keeping
            proportions. 'contain' and 'cover' are the older names for 'fit' and
            'crop' and are still accepted. Always targets the whole print area.
            Belongs to a uuid target, and cannot be combined with an explicit
            width and height.
        offset_x:
          type: number
          description: >-
            Horizontal offset in print-area pixels, measured from the anchor
            that 'position' picks, positive right. With the default position of
            'center' that anchor is the middle of the print area.
          default: 0
        offset_y:
          type: number
          description: >-
            Vertical offset in print-area pixels, measured from the anchor that
            'position' picks, positive down. With the default position of
            'center' that anchor is the middle of the print area.
          default: 0
        width:
          anyOf:
            - type: number
              maximum: 30000
              minimum: 1
            - type: 'null'
          description: >-
            Artwork width in target pixels. Must be sent together with 'height'.
            An exact box belongs to either kind of target: send it instead of
            'fit' on a print area, or instead of 'coverage' on a surface. Width
            and height are independent, so any aspect ratio is allowed.
        height:
          anyOf:
            - type: number
              maximum: 30000
              minimum: 1
            - type: 'null'
          description: >-
            Artwork height in target pixels. Must be sent together with 'width'.
            An exact box belongs to either kind of target: send it instead of
            'fit' on a print area, or instead of 'coverage' on a surface. Width
            and height are independent, so any aspect ratio is allowed.
        rotation:
          type: number
          maximum: 360
          minimum: -360
          description: Rotation in degrees (clockwise positive)
          default: 0
      additionalProperties: false
      type: object
      title: PhotoMockupPlacement
      description: >-
        Where the artwork sits on the render target, and how big it is.


        Sizing has exactly one spelling per target. On a product surface that is

        coverage: how much of the surface the artwork spans. On a print area it
        is

        either fit, or an explicit width and height in print-area pixels; the
        two

        axes are independent, so stretching on one axis only is a supported

        placement rather than an error, which is what makes this path as free as

        the PSD path.


        Every option has exactly one spelling: offset_x, offset_y and rotation.

        A second accepted spelling for the same option would let two callers
        write

        the same placement two ways and force a precedence rule to break the
        tie,

        so unrecognised keys are rejected rather than translated.


        Every pixel length here is a print-area pixel: the frame is the bounding

        box of the print area's own four corner points, in the pixels of the

        product photo the mockup was built from. It is not a fraction of
        anything,

        and image_size does not change it. That bounding box is also the
        boundary

        the artwork is composited within.


        rotation is applied before the artwork is positioned, and a rotated
        artwork

        occupies its rotated bounding box: a 100x50 box sent with rotation 45
        lands

        as a 106x106 footprint. width and height describe the box before
        rotation.
    PhotoMockupPrintFile:
      properties:
        export_path:
          type: string
          description: Public URL of the rendered output
        duration_ms:
          anyOf:
            - type: integer
            - type: 'null'
          description: Render duration in milliseconds
        export_format:
          anyOf:
            - type: string
            - type: 'null'
          description: Output format used (png, jpg, webp)
      type: object
      required:
        - export_path
      title: PhotoMockupPrintFile
      description: AI render output file
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: x-api-key
      description: >-
        API key with sm_ prefix. Get your key at
        https://sudomock.com/dashboard/api-keys

````