> ## 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 video mockup

> Animates a mockup: produces a still render from the given smart objects, then animates it. Returns 202 with a job_id to poll (GET /api/v1/jobs/{job_id}).

<RequestExample>
  ```js Node.js theme={"theme":{"light":"github-light","dark":"vesper"}}
  const response = await fetch("https://api.sudomock.com/api/v1/renders/video", {
    method: "POST",
    headers: {
      "x-api-key": "sm_your_api_key",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      "mockup_uuid": "123e4567-e89b-12d3-a456-426614174000",
      "smart_objects": [
        {
          "asset": {
            "fit": "fill",
            "url": "https://example.com/user-design.png"
          },
          "uuid": "223e4567-e89b-12d3-a456-426614174001"
        }
      ],
      "video": {
        "audio": false,
        "duration_seconds": 4,
        "motion": "ambient",
        "advanced_model": null
      },
      "webhook": {
        "url": "https://example.com/hooks/render-done"
      }
    }),
  });

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

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

  $payload = <<<'JSON'
  {
    "mockup_uuid": "123e4567-e89b-12d3-a456-426614174000",
    "smart_objects": [
      {
        "asset": {
          "fit": "fill",
          "url": "https://example.com/user-design.png"
        },
        "uuid": "223e4567-e89b-12d3-a456-426614174001"
      }
    ],
    "video": {
      "audio": false,
      "duration_seconds": 4,
      "motion": "ambient",
      "advanced_model": null
    },
    "webhook": {
      "url": "https://example.com/hooks/render-done"
    }
  }
  JSON;

  $ch = curl_init("https://api.sudomock.com/api/v1/renders/video");
  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 = {
      "mockup_uuid": "123e4567-e89b-12d3-a456-426614174000",
      "smart_objects": [
          {
              "asset": {
                  "fit": "fill",
                  "url": "https://example.com/user-design.png"
              },
              "uuid": "223e4567-e89b-12d3-a456-426614174001"
          }
      ],
      "video": {
          "audio": false,
          "duration_seconds": 4,
          "motion": "ambient",
          "advanced_model": null
      },
      "webhook": {
          "url": "https://example.com/hooks/render-done"
      }
  }

  response = requests.post(
      "https://api.sudomock.com/api/v1/renders/video",
      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/renders/video")
  request = Net::HTTP::Post.new(uri)
  request["x-api-key"] = "sm_your_api_key"
  request["Content-Type"] = "application/json"

  request.body = <<~JSON
    {
      "mockup_uuid": "123e4567-e89b-12d3-a456-426614174000",
      "smart_objects": [
        {
          "asset": {
            "fit": "fill",
            "url": "https://example.com/user-design.png"
          },
          "uuid": "223e4567-e89b-12d3-a456-426614174001"
        }
      ],
      "video": {
        "audio": false,
        "duration_seconds": 4,
        "motion": "ambient",
        "advanced_model": null
      },
      "webhook": {
        "url": "https://example.com/hooks/render-done"
      }
    }
  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(`{
    "mockup_uuid": "123e4567-e89b-12d3-a456-426614174000",
    "smart_objects": [
      {
        "asset": {
          "fit": "fill",
          "url": "https://example.com/user-design.png"
        },
        "uuid": "223e4567-e89b-12d3-a456-426614174001"
      }
    ],
    "video": {
      "audio": false,
      "duration_seconds": 4,
      "motion": "ambient",
      "advanced_model": null
    },
    "webhook": {
      "url": "https://example.com/hooks/render-done"
    }
  }`)

  	req, err := http.NewRequest("POST", "https://api.sudomock.com/api/v1/renders/video", 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 = """
  {
    "mockup_uuid": "123e4567-e89b-12d3-a456-426614174000",
    "smart_objects": [
      {
        "asset": {
          "fit": "fill",
          "url": "https://example.com/user-design.png"
        },
        "uuid": "223e4567-e89b-12d3-a456-426614174001"
      }
    ],
    "video": {
      "audio": false,
      "duration_seconds": 4,
      "motion": "ambient",
      "advanced_model": null
    },
    "webhook": {
      "url": "https://example.com/hooks/render-done"
    }
  }
  """;

  HttpRequest request = HttpRequest.newBuilder()
      .uri(URI.create("https://api.sudomock.com/api/v1/renders/video"))
      .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 = """
  {
    "mockup_uuid": "123e4567-e89b-12d3-a456-426614174000",
    "smart_objects": [
      {
        "asset": {
          "fit": "fill",
          "url": "https://example.com/user-design.png"
        },
        "uuid": "223e4567-e89b-12d3-a456-426614174001"
      }
    ],
    "video": {
      "audio": false,
      "duration_seconds": 4,
      "motion": "ambient",
      "advanced_model": null
    },
    "webhook": {
      "url": "https://example.com/hooks/render-done"
    }
  }
  """;

  var request = new HttpRequestMessage(HttpMethod.Post, "https://api.sudomock.com/api/v1/renders/video");
  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/renders/video" \
    -H "x-api-key: sm_your_api_key" \
    -H "Content-Type: application/json" \
    -d '{
      "mockup_uuid": "123e4567-e89b-12d3-a456-426614174000",
      "smart_objects": [
        {
          "asset": {
            "fit": "fill",
            "url": "https://example.com/user-design.png"
          },
          "uuid": "223e4567-e89b-12d3-a456-426614174001"
        }
      ],
      "video": {
        "audio": false,
        "duration_seconds": 4,
        "motion": "ambient",
        "advanced_model": null
      },
      "webhook": {
        "url": "https://example.com/hooks/render-done"
      }
    }'
  ```
</RequestExample>


## OpenAPI

````yaml openapi.json POST /api/v1/renders/video
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/renders/video:
    post:
      tags:
        - Video mockups
      summary: Render a video mockup
      description: >-
        Animates a mockup: produces a still render from the given smart objects,
        then animates it. Returns 202 with a job_id to poll (GET
        /api/v1/jobs/{job_id}).
      operationId: render_video_api_v1_renders_video_post
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/VideoRenderRequest'
      responses:
        '202':
          description: Successful Response
          content:
            application/json:
              schema: {}
      security:
        - ApiKeyAuth: []
      x-codeSamples:
        - lang: Node.js
          source: >-
            const response = await
            fetch("https://api.sudomock.com/api/v1/renders/video", {
              method: "POST",
              headers: {
                "x-api-key": "sm_your_api_key",
                "Content-Type": "application/json",
              },
              body: JSON.stringify({
                "mockup_uuid": "123e4567-e89b-12d3-a456-426614174000",
                "smart_objects": [
                  {
                    "asset": {
                      "fit": "fill",
                      "url": "https://example.com/user-design.png"
                    },
                    "uuid": "223e4567-e89b-12d3-a456-426614174001"
                  }
                ],
                "video": {
                  "audio": false,
                  "duration_seconds": 4,
                  "motion": "ambient",
                  "advanced_model": null
                },
                "webhook": {
                  "url": "https://example.com/hooks/render-done"
                }
              }),
            });


            const data = await response.json();

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

            $payload = <<<'JSON'
            {
              "mockup_uuid": "123e4567-e89b-12d3-a456-426614174000",
              "smart_objects": [
                {
                  "asset": {
                    "fit": "fill",
                    "url": "https://example.com/user-design.png"
                  },
                  "uuid": "223e4567-e89b-12d3-a456-426614174001"
                }
              ],
              "video": {
                "audio": false,
                "duration_seconds": 4,
                "motion": "ambient",
                "advanced_model": null
              },
              "webhook": {
                "url": "https://example.com/hooks/render-done"
              }
            }
            JSON;

            $ch = curl_init("https://api.sudomock.com/api/v1/renders/video");
            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 = {
                "mockup_uuid": "123e4567-e89b-12d3-a456-426614174000",
                "smart_objects": [
                    {
                        "asset": {
                            "fit": "fill",
                            "url": "https://example.com/user-design.png"
                        },
                        "uuid": "223e4567-e89b-12d3-a456-426614174001"
                    }
                ],
                "video": {
                    "audio": false,
                    "duration_seconds": 4,
                    "motion": "ambient",
                    "advanced_model": null
                },
                "webhook": {
                    "url": "https://example.com/hooks/render-done"
                }
            }

            response = requests.post(
                "https://api.sudomock.com/api/v1/renders/video",
                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/renders/video")

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

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

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


            request.body = <<~JSON
              {
                "mockup_uuid": "123e4567-e89b-12d3-a456-426614174000",
                "smart_objects": [
                  {
                    "asset": {
                      "fit": "fill",
                      "url": "https://example.com/user-design.png"
                    },
                    "uuid": "223e4567-e89b-12d3-a456-426614174001"
                  }
                ],
                "video": {
                  "audio": false,
                  "duration_seconds": 4,
                  "motion": "ambient",
                  "advanced_model": null
                },
                "webhook": {
                  "url": "https://example.com/hooks/render-done"
                }
              }
            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  \"mockup_uuid\": \"123e4567-e89b-12d3-a456-426614174000\",\n  \"smart_objects\": [\n    {\n      \"asset\": {\n        \"fit\": \"fill\",\n        \"url\": \"https://example.com/user-design.png\"\n      },\n      \"uuid\": \"223e4567-e89b-12d3-a456-426614174001\"\n    }\n  ],\n  \"video\": {\n    \"audio\": false,\n    \"duration_seconds\": 4,\n    \"motion\": \"ambient\",\n    \"advanced_model\": null\n  },\n  \"webhook\": {\n    \"url\": \"https://example.com/hooks/render-done\"\n  }\n}`)\n\n\treq, err := http.NewRequest(\"POST\", \"https://api.sudomock.com/api/v1/renders/video\", 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 = """
            {
              "mockup_uuid": "123e4567-e89b-12d3-a456-426614174000",
              "smart_objects": [
                {
                  "asset": {
                    "fit": "fill",
                    "url": "https://example.com/user-design.png"
                  },
                  "uuid": "223e4567-e89b-12d3-a456-426614174001"
                }
              ],
              "video": {
                "audio": false,
                "duration_seconds": 4,
                "motion": "ambient",
                "advanced_model": null
              },
              "webhook": {
                "url": "https://example.com/hooks/render-done"
              }
            }
            """;

            HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://api.sudomock.com/api/v1/renders/video"))
                .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 = """

            {
              "mockup_uuid": "123e4567-e89b-12d3-a456-426614174000",
              "smart_objects": [
                {
                  "asset": {
                    "fit": "fill",
                    "url": "https://example.com/user-design.png"
                  },
                  "uuid": "223e4567-e89b-12d3-a456-426614174001"
                }
              ],
              "video": {
                "audio": false,
                "duration_seconds": 4,
                "motion": "ambient",
                "advanced_model": null
              },
              "webhook": {
                "url": "https://example.com/hooks/render-done"
              }
            }

            """;


            var request = new HttpRequestMessage(HttpMethod.Post,
            "https://api.sudomock.com/api/v1/renders/video");

            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/renders/video" \
              -H "x-api-key: sm_your_api_key" \
              -H "Content-Type: application/json" \
              -d '{
                "mockup_uuid": "123e4567-e89b-12d3-a456-426614174000",
                "smart_objects": [
                  {
                    "asset": {
                      "fit": "fill",
                      "url": "https://example.com/user-design.png"
                    },
                    "uuid": "223e4567-e89b-12d3-a456-426614174001"
                  }
                ],
                "video": {
                  "audio": false,
                  "duration_seconds": 4,
                  "motion": "ambient",
                  "advanced_model": null
                },
                "webhook": {
                  "url": "https://example.com/hooks/render-done"
                }
              }'
components:
  schemas:
    VideoRenderRequest:
      properties:
        mockup_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: >-
            RENDER MODE: UUID of the mockup to animate (from GET
            /api/v1/psd-mockups or POST /api/v1/psd/upload). Required in render
            mode; omit in raw-image mode.
        smart_objects:
          anyOf:
            - items:
                $ref: '#/components/schemas/SmartObjectInput'
              type: array
              minItems: 1
            - type: 'null'
          description: >-
            RENDER MODE: smart objects with their assets, identical to a still
            render (at least 1 required). Required in render mode; omit in
            raw-image mode.
        export_options:
          $ref: '#/components/schemas/ExportOptions'
          description: >-
            RENDER MODE: still-render export configuration (the i2v input
            frame). Format/size/quality. Ignored in raw-image mode.
        image_url:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            RAW-IMAGE MODE: a public https png/jpg URL to animate directly
            (general image-to-video, no render). Supply this OR (mockup_uuid +
            smart_objects), never both.
        video:
          $ref: '#/components/schemas/VideoOptions'
          description: >-
            Animation options (duration, audio, motion, optional advanced_model
            override).
        webhook:
          anyOf:
            - additionalProperties: true
              type: object
            - type: 'null'
          description: >-
            Optional completion webhook, e.g. {"url": "https://..."}.
            Best-effort push; poll (GET /api/v1/jobs/{job_id}) remains the
            source of truth.
      type: object
      title: VideoRenderRequest
      description: >-
        Request body for POST /api/v1/renders/video.


        Supply exactly one of two input modes. Render mode (mockup_uuid and

        smart_objects, optionally export_options) mirrors a still render: the

        still is produced first, then animated. Raw-image mode

        (image_url) animates a public https png or jpg directly with no render

        step, and the render fields are ignored.


        Both modes take the video animation options and an optional completion

        webhook. The call always queues a job; poll GET /api/v1/jobs/{job_id}
        for

        the result. Sending both modes, or neither, returns 400.
      example:
        mockup_uuid: 123e4567-e89b-12d3-a456-426614174000
        smart_objects:
          - asset:
              fit: fill
              url: https://example.com/user-design.png
            uuid: 223e4567-e89b-12d3-a456-426614174001
        video:
          audio: false
          duration_seconds: 4
          motion: ambient
          advanced_model: null
        webhook:
          url: https://example.com/hooks/render-done
    SmartObjectInput:
      properties:
        uuid:
          type: string
          pattern: ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$
          description: UUID of the smart object to render
          examples:
            - b41a7e52-93c8-4d61-8f07-2ae5c9d04713
        asset:
          anyOf:
            - $ref: '#/components/schemas/AssetInput'
            - type: 'null'
          description: Asset configuration (image to place)
        color:
          anyOf:
            - $ref: '#/components/schemas/ColorOverlay'
            - type: 'null'
          description: Color overlay configuration
        adjustment_layers:
          anyOf:
            - $ref: '#/components/schemas/AdjustmentLayers'
            - type: 'null'
          description: >-
            Image adjustments applied to your artwork after the fit transform
            and before it is blended into the mockup. PSD-level adjustment
            layers are not affected.
      type: object
      required:
        - uuid
      title: SmartObjectInput
      description: One smart object and what goes into it.
      example:
        asset:
          fit: fill
          rotate: 0
          url: https://example.com/user-design.png
        color:
          blending_mode: multiply
          hex: '#FF5733'
        uuid: 223e4567-e89b-12d3-a456-426614174001
    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
    VideoOptions:
      properties:
        duration_seconds:
          type: integer
          maximum: 15
          minimum: 1
          description: >-
            Clip length in seconds chosen by the customer. Must be one of the
            supported durations; the endpoint rejects an unsupported value with
            400. The credit cost scales with this value.
          default: 4
        audio:
          type: boolean
          description: >-
            Generate sound with the clip. Default OFF (muted clips are cheaper).
            Audio increases the credit cost on models that charge an audio
            premium. Note: motion='showcase' always includes sound, so the
            endpoint treats it as audio=true and prices it accordingly.
          default: false
        motion:
          type: string
          enum:
            - ambient
            - showcase
          description: >-
            'ambient' = subtle looping hero motion that keeps the print readable
            (muted unless audio=true); 'showcase' = one deliberate cinematic
            camera/product move, always with sound (priced as audio=true).
          default: ambient
        advanced_model:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            Advanced override for the automatic quality selection. Unsupported
            values are rejected. null = automatic (recommended).
      type: object
      title: VideoOptions
      description: >-
        Animation options for a POST /renders/video request.


        The still is produced from the same mockup_uuid + smart_objects payload
        as a

        normal render, then animated into a short video. SudoMock picks the best
        video

        model for the image automatically; `advanced_model` is an optional
        override.


        You choose `duration_seconds` and `audio`, and the credit cost scales
        with both.

        `duration_seconds` must be one of the chosen model's allowed durations,
        or the

        endpoint returns 400 INVALID_VIDEO_DURATION otherwise. The 1..15 range
        here is a

        coarse guard; the exact allowed set depends on the model.
    AssetInput:
      properties:
        url:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            URL to the user's image (HTTP/HTTPS or data: URL). Either url or
            base64 must be provided. Server downloads the image, adding network
            latency.
          examples:
            - https://example.com/user-design.png
        base64:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            Raw base64-encoded image bytes (no data: prefix). RECOMMENDED for
            best performance: eliminates server-side download latency (50-500ms
            faster than URL). Either url or base64 must be provided.
        content_type:
          anyOf:
            - type: string
              pattern: ^image/(png|jpeg|webp|gif)$
            - type: 'null'
          description: >-
            MIME type when using base64 field. Supported: image/png, image/jpeg,
            image/webp, image/gif. Defaults to image/png if omitted.
          examples:
            - image/png
        fit:
          type: string
          enum:
            - fill
            - fit
            - crop
          description: >-
            How the artwork meets the smart object area. 'fit' scales it until
            it fits inside, keeping proportions, which can leave empty space.
            'fill' stretches it to the bounds and does not keep its 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. Defaults to 'fit': a caller who says nothing is
            not asking to have their artwork distorted, and a silently stretched
            design is a defect the caller cannot see.
          default: fit
        size:
          anyOf:
            - $ref: '#/components/schemas/AssetSize'
            - type: 'null'
          description: >-
            Custom size override in pixels. Width and height are both optional
            and each must be at least 1 pixel.
        position:
          anyOf:
            - $ref: '#/components/schemas/AssetPosition'
            - type: 'null'
          description: >-
            Custom position override (top/left in pixels). The top-left corner
            of the size box, which stays axis-aligned: rotate turns the artwork
            inside it, never the box.
        rotate:
          type: number
          maximum: 360
          minimum: -360
          description: >-
            Rotation angle in degrees (clockwise positive). Applied to the
            artwork before it is fitted, so the turned artwork, corners
            included, is what fit places inside the still axis-aligned size box
            at position.
          default: 0
          examples:
            - 15
        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
      type: object
      title: AssetInput
      description: >-
        The image to place into a smart object, and how it should sit there.


        Image source priority: base64 > url (including data: URLs)

        - base64: Raw base64 string (no data: prefix). Most efficient for inline
        images.

        - url: HTTP/HTTPS URL or data:image/...;base64,... URL.
      example:
        fit: fill
        flip_horizontal: false
        flip_vertical: false
        position:
          left: 20
          top: 10
        rotate: 15
        size:
          height: 600
          width: 800
        url: https://example.com/user-design.png
    ColorOverlay:
      properties:
        hex:
          anyOf:
            - type: string
              pattern: ^#[0-9A-Fa-f]{6}$
            - type: 'null'
          description: Hex color code (e.g., '#FF5733'). Send this or 'label'.
          examples:
            - '#FF5733'
        label:
          anyOf:
            - type: string
              maxLength: 32
              minLength: 1
            - type: 'null'
          description: >-
            One of the colours saved on this mockup, by the name you gave it.
            Send this instead of 'hex' to keep calling a colour what your own
            catalogue calls it. Names match exactly, and are set with PATCH
            /api/v1/psd-mockups/{uuid}.
        blending_mode:
          type: string
          description: >-
            Blend mode for color overlay. Common values: 'normal', 'multiply'
            (fabric/textile mockups), 'screen', 'overlay', 'soft_light'. All 27
            Photoshop blend modes supported.
          default: normal
          examples:
            - multiply
      type: object
      title: ColorOverlay
      description: A colour laid over the smart object, with a blending mode.
      example:
        blending_mode: multiply
        hex: '#FF5733'
    AdjustmentLayers:
      properties:
        brightness:
          type: integer
          maximum: 150
          minimum: -150
          description: Brightness adjustment (-150 to 150). 0=no change.
          default: 0
        contrast:
          type: integer
          maximum: 100
          minimum: -100
          description: Contrast adjustment (-100 to 100). 0=no change.
          default: 0
        opacity:
          type: integer
          maximum: 100
          minimum: 0
          description: >-
            Artwork opacity (0=fully transparent, 100=fully opaque). Default
            100.
          default: 100
        saturation:
          type: integer
          maximum: 100
          minimum: -100
          description: Saturation adjustment (-100 to 100). 0=no change, -100=grayscale.
          default: 0
        vibrance:
          type: integer
          maximum: 100
          minimum: -100
          description: >-
            Vibrance adjustment (-100 to 100). Similar to saturation but
            preserves skin tones.
          default: 0
        blur:
          type: integer
          maximum: 100
          minimum: 0
          description: >-
            Gaussian blur amount (0=sharp, 100=max blur). Useful for background
            effects.
          default: 0
      type: object
      title: AdjustmentLayers
      description: >-
        Image adjustment parameters applied to the user's artwork before
        blending into the mockup.

        Applied after fit transformation, does not affect PSD-level adjustments.
    AssetSize:
      properties:
        width:
          anyOf:
            - type: number
              minimum: 1
            - type: 'null'
          description: Custom width in pixels
          examples:
            - 800
        height:
          anyOf:
            - type: number
              minimum: 1
            - type: 'null'
          description: Custom height in pixels
          examples:
            - 600
      type: object
      title: AssetSize
      description: >-
        How large the artwork is drawn inside the smart object.


        Fractional pixels are accepted. A canvas editor places by dragging and

        scales by ratio, so the exact placement a seller sees is continuous;
        asking

        them to round it first is asking them to send a placement that is not
        the

        one on their screen. The renderer already carries these through the

        embedded-to-bbox transform as floats and rounds once at the end, which
        is

        strictly more accurate than rounding before the transform.
    AssetPosition:
      properties:
        top:
          anyOf:
            - type: number
            - type: 'null'
          description: Top offset in pixels
          examples:
            - 100
        left:
          anyOf:
            - type: number
            - type: 'null'
          description: Left offset in pixels
          examples:
            - 100
      type: object
      title: AssetPosition
      description: |-
        Where the artwork sits inside the smart object.

        Fractional pixels are accepted, for the same reason as AssetSize.
  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

````