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

> Renders a mockup by compositing layers with user-provided images.

<RequestExample>
  ```js Node.js theme={"theme":{"light":"github-light","dark":"vesper"}}
  const response = await fetch("https://api.sudomock.com/api/v1/renders", {
    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
      },
      "mockup_uuid": "123e4567-e89b-12d3-a456-426614174000",
      "smart_objects": [
        {
          "asset": {
            "fit": "fill",
            "position": {
              "left": 100,
              "top": 100
            },
            "rotate": 0,
            "size": {
              "height": 600,
              "width": 800
            },
            "url": "https://example.com/user-design.png"
          },
          "color": {
            "blending_mode": "multiply",
            "hex": "#FFFFFF"
          },
          "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
    },
    "mockup_uuid": "123e4567-e89b-12d3-a456-426614174000",
    "smart_objects": [
      {
        "asset": {
          "fit": "fill",
          "position": {
            "left": 100,
            "top": 100
          },
          "rotate": 0,
          "size": {
            "height": 600,
            "width": 800
          },
          "url": "https://example.com/user-design.png"
        },
        "color": {
          "blending_mode": "multiply",
          "hex": "#FFFFFF"
        },
        "uuid": "223e4567-e89b-12d3-a456-426614174001"
      }
    ]
  }
  JSON;

  $ch = curl_init("https://api.sudomock.com/api/v1/renders");
  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
      },
      "mockup_uuid": "123e4567-e89b-12d3-a456-426614174000",
      "smart_objects": [
          {
              "asset": {
                  "fit": "fill",
                  "position": {
                      "left": 100,
                      "top": 100
                  },
                  "rotate": 0,
                  "size": {
                      "height": 600,
                      "width": 800
                  },
                  "url": "https://example.com/user-design.png"
              },
              "color": {
                  "blending_mode": "multiply",
                  "hex": "#FFFFFF"
              },
              "uuid": "223e4567-e89b-12d3-a456-426614174001"
          }
      ]
  }

  response = requests.post(
      "https://api.sudomock.com/api/v1/renders",
      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")
  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
      },
      "mockup_uuid": "123e4567-e89b-12d3-a456-426614174000",
      "smart_objects": [
        {
          "asset": {
            "fit": "fill",
            "position": {
              "left": 100,
              "top": 100
            },
            "rotate": 0,
            "size": {
              "height": 600,
              "width": 800
            },
            "url": "https://example.com/user-design.png"
          },
          "color": {
            "blending_mode": "multiply",
            "hex": "#FFFFFF"
          },
          "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
    },
    "mockup_uuid": "123e4567-e89b-12d3-a456-426614174000",
    "smart_objects": [
      {
        "asset": {
          "fit": "fill",
          "position": {
            "left": 100,
            "top": 100
          },
          "rotate": 0,
          "size": {
            "height": 600,
            "width": 800
          },
          "url": "https://example.com/user-design.png"
        },
        "color": {
          "blending_mode": "multiply",
          "hex": "#FFFFFF"
        },
        "uuid": "223e4567-e89b-12d3-a456-426614174001"
      }
    ]
  }`)

  	req, err := http.NewRequest("POST", "https://api.sudomock.com/api/v1/renders", 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
    },
    "mockup_uuid": "123e4567-e89b-12d3-a456-426614174000",
    "smart_objects": [
      {
        "asset": {
          "fit": "fill",
          "position": {
            "left": 100,
            "top": 100
          },
          "rotate": 0,
          "size": {
            "height": 600,
            "width": 800
          },
          "url": "https://example.com/user-design.png"
        },
        "color": {
          "blending_mode": "multiply",
          "hex": "#FFFFFF"
        },
        "uuid": "223e4567-e89b-12d3-a456-426614174001"
      }
    ]
  }
  """;

  HttpRequest request = HttpRequest.newBuilder()
      .uri(URI.create("https://api.sudomock.com/api/v1/renders"))
      .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
    },
    "mockup_uuid": "123e4567-e89b-12d3-a456-426614174000",
    "smart_objects": [
      {
        "asset": {
          "fit": "fill",
          "position": {
            "left": 100,
            "top": 100
          },
          "rotate": 0,
          "size": {
            "height": 600,
            "width": 800
          },
          "url": "https://example.com/user-design.png"
        },
        "color": {
          "blending_mode": "multiply",
          "hex": "#FFFFFF"
        },
        "uuid": "223e4567-e89b-12d3-a456-426614174001"
      }
    ]
  }
  """;

  var request = new HttpRequestMessage(HttpMethod.Post, "https://api.sudomock.com/api/v1/renders");
  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" \
    -H "x-api-key: sm_your_api_key" \
    -H "Content-Type: application/json" \
    -d '{
      "export_options": {
        "image_format": "webp",
        "image_size": 1920,
        "quality": 95
      },
      "mockup_uuid": "123e4567-e89b-12d3-a456-426614174000",
      "smart_objects": [
        {
          "asset": {
            "fit": "fill",
            "position": {
              "left": 100,
              "top": 100
            },
            "rotate": 0,
            "size": {
              "height": 600,
              "width": 800
            },
            "url": "https://example.com/user-design.png"
          },
          "color": {
            "blending_mode": "multiply",
            "hex": "#FFFFFF"
          },
          "uuid": "223e4567-e89b-12d3-a456-426614174001"
        }
      ]
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json Response theme={"theme":{"light":"github-light","dark":"vesper"}}
  {
    "data": {
      "print_files": [
        {
          "export_path": "https://cdn.sudomock.com/renders/c315f78f-d2c7-4541-b240-a9372842de94/render_8f2c1d4e.webp",
          "smart_object_uuid": "223e4567-e89b-12d3-a456-426614174001"
        }
      ]
    },
    "success": true
  }
  ```
</ResponseExample>


## OpenAPI

````yaml openapi.json POST /api/v1/renders
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:
    post:
      tags:
        - PSD mockups
      summary: Render a PSD mockup
      description: Renders a mockup by compositing layers with user-provided images.
      operationId: render_mockup_api_v1_renders_post
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RenderRequest'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RenderResponse'
      security:
        - ApiKeyAuth: []
      x-codeSamples:
        - lang: Node.js
          source: >-
            const response = await
            fetch("https://api.sudomock.com/api/v1/renders", {
              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
                },
                "mockup_uuid": "123e4567-e89b-12d3-a456-426614174000",
                "smart_objects": [
                  {
                    "asset": {
                      "fit": "fill",
                      "position": {
                        "left": 100,
                        "top": 100
                      },
                      "rotate": 0,
                      "size": {
                        "height": 600,
                        "width": 800
                      },
                      "url": "https://example.com/user-design.png"
                    },
                    "color": {
                      "blending_mode": "multiply",
                      "hex": "#FFFFFF"
                    },
                    "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
              },
              "mockup_uuid": "123e4567-e89b-12d3-a456-426614174000",
              "smart_objects": [
                {
                  "asset": {
                    "fit": "fill",
                    "position": {
                      "left": 100,
                      "top": 100
                    },
                    "rotate": 0,
                    "size": {
                      "height": 600,
                      "width": 800
                    },
                    "url": "https://example.com/user-design.png"
                  },
                  "color": {
                    "blending_mode": "multiply",
                    "hex": "#FFFFFF"
                  },
                  "uuid": "223e4567-e89b-12d3-a456-426614174001"
                }
              ]
            }
            JSON;

            $ch = curl_init("https://api.sudomock.com/api/v1/renders");
            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
                },
                "mockup_uuid": "123e4567-e89b-12d3-a456-426614174000",
                "smart_objects": [
                    {
                        "asset": {
                            "fit": "fill",
                            "position": {
                                "left": 100,
                                "top": 100
                            },
                            "rotate": 0,
                            "size": {
                                "height": 600,
                                "width": 800
                            },
                            "url": "https://example.com/user-design.png"
                        },
                        "color": {
                            "blending_mode": "multiply",
                            "hex": "#FFFFFF"
                        },
                        "uuid": "223e4567-e89b-12d3-a456-426614174001"
                    }
                ]
            }

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

            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
                },
                "mockup_uuid": "123e4567-e89b-12d3-a456-426614174000",
                "smart_objects": [
                  {
                    "asset": {
                      "fit": "fill",
                      "position": {
                        "left": 100,
                        "top": 100
                      },
                      "rotate": 0,
                      "size": {
                        "height": 600,
                        "width": 800
                      },
                      "url": "https://example.com/user-design.png"
                    },
                    "color": {
                      "blending_mode": "multiply",
                      "hex": "#FFFFFF"
                    },
                    "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  \"mockup_uuid\": \"123e4567-e89b-12d3-a456-426614174000\",\n  \"smart_objects\": [\n    {\n      \"asset\": {\n        \"fit\": \"fill\",\n        \"position\": {\n          \"left\": 100,\n          \"top\": 100\n        },\n        \"rotate\": 0,\n        \"size\": {\n          \"height\": 600,\n          \"width\": 800\n        },\n        \"url\": \"https://example.com/user-design.png\"\n      },\n      \"color\": {\n        \"blending_mode\": \"multiply\",\n        \"hex\": \"#FFFFFF\"\n      },\n      \"uuid\": \"223e4567-e89b-12d3-a456-426614174001\"\n    }\n  ]\n}`)\n\n\treq, err := http.NewRequest(\"POST\", \"https://api.sudomock.com/api/v1/renders\", 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
              },
              "mockup_uuid": "123e4567-e89b-12d3-a456-426614174000",
              "smart_objects": [
                {
                  "asset": {
                    "fit": "fill",
                    "position": {
                      "left": 100,
                      "top": 100
                    },
                    "rotate": 0,
                    "size": {
                      "height": 600,
                      "width": 800
                    },
                    "url": "https://example.com/user-design.png"
                  },
                  "color": {
                    "blending_mode": "multiply",
                    "hex": "#FFFFFF"
                  },
                  "uuid": "223e4567-e89b-12d3-a456-426614174001"
                }
              ]
            }
            """;

            HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://api.sudomock.com/api/v1/renders"))
                .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
              },
              "mockup_uuid": "123e4567-e89b-12d3-a456-426614174000",
              "smart_objects": [
                {
                  "asset": {
                    "fit": "fill",
                    "position": {
                      "left": 100,
                      "top": 100
                    },
                    "rotate": 0,
                    "size": {
                      "height": 600,
                      "width": 800
                    },
                    "url": "https://example.com/user-design.png"
                  },
                  "color": {
                    "blending_mode": "multiply",
                    "hex": "#FFFFFF"
                  },
                  "uuid": "223e4567-e89b-12d3-a456-426614174001"
                }
              ]
            }

            """;


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

            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" \
              -H "x-api-key: sm_your_api_key" \
              -H "Content-Type: application/json" \
              -d '{
                "export_options": {
                  "image_format": "webp",
                  "image_size": 1920,
                  "quality": 95
                },
                "mockup_uuid": "123e4567-e89b-12d3-a456-426614174000",
                "smart_objects": [
                  {
                    "asset": {
                      "fit": "fill",
                      "position": {
                        "left": 100,
                        "top": 100
                      },
                      "rotate": 0,
                      "size": {
                        "height": 600,
                        "width": 800
                      },
                      "url": "https://example.com/user-design.png"
                    },
                    "color": {
                      "blending_mode": "multiply",
                      "hex": "#FFFFFF"
                    },
                    "uuid": "223e4567-e89b-12d3-a456-426614174001"
                  }
                ]
              }'
components:
  schemas:
    RenderRequest:
      properties:
        mockup_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 mockup to render. Must be a valid UUID, for example
            c315f78f-d2c7-4541-b240-a9372842de94. Obtained from the POST
            /api/v1/psd/upload or GET /api/v1/psd-mockups response.
          examples:
            - c315f78f-d2c7-4541-b240-a9372842de94
        smart_objects:
          items:
            $ref: '#/components/schemas/SmartObjectInput'
          type: array
          description: >-
            List of smart objects with their assets. Required unless text_layers
            or group_layers is provided.
        text_layers:
          anyOf:
            - items:
                $ref: '#/components/schemas/TextLayerInput'
              type: array
              maxItems: 50
            - type: 'null'
          description: >-
            Up to 50 text-layer overrides. Each entry targets a text-layer UUID
            and provides exactly one of text for a single-style layer or
            segments for a mixed-style layer. Omitted layers and styling fields
            keep their authored values.
        group_layers:
          anyOf:
            - items:
                $ref: '#/components/schemas/GroupLayerInput'
              type: array
              maxItems: 50
            - type: 'null'
          description: >-
            Group outline overrides. Each entry addresses a listed group by its
            own UUID; the change affects everything inside that group.
        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.
        export_label:
          anyOf:
            - type: string
              maxLength: 100
            - type: 'null'
          description: >-
            Optional label for export file naming (max 100 chars, alphanumeric +
            hyphen/underscore)
          examples:
            - summer-tee-front
        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). If false (default), the render runs
            synchronously and returns the result.
          default: false
      type: object
      required:
        - mockup_uuid
      title: RenderRequest
      description: 'What to render: which mockup, what goes into it, and how to export it.'
      example:
        export_options:
          image_format: webp
          image_size: 1920
          quality: 95
        mockup_uuid: 123e4567-e89b-12d3-a456-426614174000
        smart_objects:
          - asset:
              fit: fill
              position:
                left: 100
                top: 100
              rotate: 0
              size:
                height: 600
                width: 800
              url: https://example.com/user-design.png
            color:
              blending_mode: multiply
              hex: '#FFFFFF'
            uuid: 223e4567-e89b-12d3-a456-426614174001
    RenderResponse:
      properties:
        data:
          $ref: '#/components/schemas/RenderResponseData'
          description: Response data
        success:
          type: boolean
          description: Success status
          default: true
        warnings:
          anyOf:
            - items:
                $ref: '#/components/schemas/RenderWarning'
              type: array
            - type: 'null'
          description: >-
            Non-fatal advisories about this render (e.g. requested size above
            the mockup's native resolution). Omitted when none.
          examples:
            - - code: OUTPUT_EXCEEDS_MAX_RESOLUTION
                message: >-
                  Requested 4096px is above this mockup's native 3000px. The
                  result is enlarged and may look softer than its native
                  resolution. For the sharpest output, request 3000px or less.
      type: object
      required:
        - data
      title: RenderResponse
      description: The finished render and where to fetch it.
      example:
        data:
          print_files:
            - export_path: >-
                https://cdn.sudomock.com/mockup-assets/renders/c315f78f-d2c7-4541-b240-a9372842de94/render_8f2c1d4e.webp
              smart_object_uuid: 223e4567-e89b-12d3-a456-426614174001
        success: true
    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
    TextLayerInput:
      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 text layer to update (from the upload/detail response
            text_layers list)
          examples:
            - 4d7f1a2e-6c83-4b19-9e5a-2f0c8d3b6471
        text:
          anyOf:
            - type: string
              maxLength: 500
              minLength: 1
            - type: 'null'
          description: >-
            Replacement text (1-500 characters) for single-style layers
            (segment_count = 1)
          examples:
            - Isabella
        segments:
          anyOf:
            - items:
                $ref: '#/components/schemas/TextSegmentInput'
              type: array
              maxItems: 32
              minItems: 1
            - type: 'null'
          description: >-
            Styled-segment overrides for multi-style layers (segment_count > 1).
            Override any subset by index; omitted segments keep their original
            text.
        font:
          anyOf:
            - type: string
              maxLength: 255
            - type: 'null'
          description: >-
            Font to render with: a font uuid from GET /fonts, or a PostScript
            name. Single-style layers only. Omit to keep the layer's original
            font.
          examples:
            - OpenSans-Bold
        font_size:
          anyOf:
            - type: number
              maximum: 2000
              exclusiveMinimum: 0
            - type: 'null'
          description: >-
            Font size in pixels at the mockup's native resolution. Single-style
            layers only. Omit to keep the original size.
          examples:
            - 48
        color:
          anyOf:
            - type: string
              pattern: ^#?[0-9a-fA-F]{6}$
            - type: 'null'
          description: >-
            Text color as hex, e.g. #1A1A1A. Single-style layers only. Applies
            to the color you see: when the layer's visible color comes from a
            color effect, that effect takes the new color. Omit to keep the
            original color.
          examples:
            - '#1A1A1A'
        stroke_color:
          anyOf:
            - type: string
            - items:
                anyOf:
                  - type: string
                  - type: 'null'
              type: array
            - type: 'null'
          description: >-
            Color for this text layer's own outlines. Send a hex value like
            "#FFFFFF" to recolor the front outline, or a list in stroke_count
            order (front to back). Use null to keep an outline's original color;
            extra entries are ignored. Layers with no outlines ignore this value
            with a warning. Single-style layers only. Omit to keep all original
            outline colors.
          examples:
            - '#FFFFFF'
            - - '#FFFFFF'
              - null
        fit:
          type: string
          enum:
            - shrink
            - clip
            - overflow
          description: >-
            How longer replacement text is handled for single-style point text:
            'overflow' (default) preserves the designed size and may extend
            beyond the original area; 'shrink' scales the text down to fit;
            'clip' preserves the size and cuts it at the last character that
            fits. Paragraph text continues to wrap within its box.
          default: overflow
        vertical_align:
          type: string
          enum:
            - top
            - bottom
            - center
          description: >-
            Where text that 'fit': 'shrink' scaled down sits vertically within
            the original text area: 'top' (default) keeps the designed position,
            'center' centers it in the area, 'bottom' aligns it to the area's
            bottom edge. Only applies when shrinking actually occurs;
            single-style point text only.
          default: top
      type: object
      required:
        - uuid
      title: TextLayerInput
      description: Text layer override for rendering
      example:
        color: '#FFFFFF'
        text: Isabella
        uuid: 323e4567-e89b-12d3-a456-426614174002
    GroupLayerInput:
      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 group layer to update (from the upload/detail response
            group_layers list)
          examples:
            - b2c14e08-5a7d-4f36-a91b-7e0d5c283a64
        stroke_color:
          anyOf:
            - type: string
            - items:
                anyOf:
                  - type: string
                  - type: 'null'
              type: array
          description: >-
            Color for the group's outlines. Send a hex value like "#FFFFFF" to
            recolor the front outline, or a list in stroke_count order (front to
            back). Use null to keep an outline's original color; extra entries
            are ignored. The change affects everything inside this group.
          examples:
            - '#FFFFFF'
            - - '#FFFFFF'
              - null
      type: object
      required:
        - uuid
        - stroke_color
      title: GroupLayerInput
      description: Group outline override for rendering.
    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
    RenderResponseData:
      properties:
        print_files:
          items:
            $ref: '#/components/schemas/PrintFile'
          type: array
          description: List of rendered print files
        render_uuid:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            The render's transaction id (also the async job uuid). Echoed at the
            data level for convenience; null on legacy paths.
      type: object
      required:
        - print_files
      title: RenderResponseData
      description: Data payload in render response
    RenderWarning:
      properties:
        code:
          type: string
          description: Stable advisory code
        message:
          type: string
          description: Human-readable, non-fatal advisory
      type: object
      required:
        - code
        - message
      title: RenderWarning
      description: Non-fatal advisory attached to a successful render.
    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.
    TextSegmentInput:
      properties:
        index:
          type: integer
          maximum: 31
          minimum: 0
          description: Segment to replace (0-based, from the layer's segments list)
        text:
          type: string
          maxLength: 200
          minLength: 1
          description: >-
            Replacement text for this segment (1-200 characters). The segment
            keeps its own font, size, and color.
      type: object
      required:
        - index
        - text
      title: TextSegmentInput
      description: One styled-segment override for a multi-style text layer.
    PrintFile:
      properties:
        export_path:
          type: string
          description: Path to the rendered output file
          examples:
            - >-
              https://cdn.sudomock.com/mockup-assets/renders/c315f78f-d2c7-4541-b240-a9372842de94/render_5ec56e42-4afe-4267-bf21-6f8f586d16bb.webp
        smart_object_uuid:
          type: string
          description: >-
            UUID of the first Smart Object in the request; an empty string for a
            render without Smart Objects, including text-only and group-only
            renders.
          examples:
            - 6bdc8897-3eee-4356-b717-8bc3c9249946
        render_uuid:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            The render's transaction id (also the async job uuid). Returned so
            storefront/Studio fulfillment flows can correlate the render; null
            on legacy paths.
          examples:
            - 5ec56e42-4afe-4267-bf21-6f8f586d16bb
      type: object
      required:
        - export_path
        - smart_object_uuid
      title: PrintFile
      description: Individual print file in render response
      example:
        export_path: >-
          https://cdn.sudomock.com/mockup-assets/renders/c315f78f-d2c7-4541-b240-a9372842de94/render_8f2c1d4e.webp
        smart_object_uuid: 223e4567-e89b-12d3-a456-426614174001
    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

````