---
title: "Render a photo mockup"
method: POST
path: "/api/v1/photo-mockups/{mockup_id}/render"
tags: ["Photo mockups"]
---

# Render a photo mockup

`POST /api/v1/photo-mockups/{mockup_id}/render`

## Request

- Base URL: `https://api.sudomock.com`
- URL: `https://api.sudomock.com/api/v1/photo-mockups/{mockup_id}/render`
- Auth: API key in header `x-api-key`

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.

## Path parameters

- `mockup_id` string, required: Id of the photo mockup the artwork is rendered onto.

## Request body

- PhotoMockupRender: 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.
  - `print_areas` PhotoMockupPrintAreaRender[], required: 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.
    - `uuid` string, nullable: UUID of a saved print area, a bounded zone drawn on a product.
    - `surface_uuid` string, nullable: UUID of a printable product surface. A product carrying saved print areas still has one, and it is a separate render target from them.
    - `base64` string, nullable: Base64-encoded artwork image.
    - `artwork_url` string, nullable: Artwork image URL
    - `color` string, nullable: 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}.
    - `adjustments` PhotoMockupAdjustments: Outcome-level controls for the photo mockup render.
      - `brightness` integer: Brightness applied to the artwork, from -150 to 150, where 0 keeps it unchanged.
      - `contrast` integer: Contrast applied to the artwork, from -100 to 100, where 0 keeps it unchanged.
      - `opacity` integer: How opaque the artwork is, from 0 for fully transparent to 100 for opaque.
      - `saturation` integer: Saturation applied to the artwork, from -100 for grayscale to 100 for fully saturated.
      - `vibrance` integer: Saturation that affects muted colors more than already vivid ones, from -100 to 100.
      - `blur` number: Softens the artwork, from 0 for sharp to 100 for the strongest blur.
      - `blend_mode` 'multiply' | 'normal' | 'screen' | 'lighten' | 'soft_light' | 'overlay' | 'darken': 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.
    - `placement` PhotoMockupPlacement: 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. The artwork is cut to the print area itself, its own four-cornered outline and its mask, not to that bounding box. 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.
      - `position` 'center' | 'top_left' | 'top_center' | 'top_right' | 'center_left' | 'center_right' | 'left_center' | 'right_center' | 'bottom_left' | 'bottom_center' | 'bottom_right': Predefined position within print area
      - `coverage` integer, nullable: 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` 'fill' | 'fit' | 'crop', nullable: 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` number: 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.
      - `offset_y` number: 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.
      - `width` number, nullable: 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` number, nullable: 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` number: Rotation in degrees (clockwise positive)
    - `flip_horizontal` boolean: Flip artwork horizontally (left-right mirror)
    - `flip_vertical` boolean: Flip artwork vertically (top-bottom mirror)
    - `remove_background` boolean: 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.
  - `export_options` PhotoMockupExportOptions: Format, size and quality of a photo mockup render.
    - `image_format` 'png' | 'jpg' | 'webp': Output format: 'webp' (30-70% smaller, recommended), 'png' (lossless), 'jpg' (smallest, no transparency)
    - `image_size` integer: Length of the output's longer side in pixels (100-10000); the other side follows the product photo's proportions. 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 size.
    - `quality` integer: Compression quality for JPG/WebP (1-100). Ignored for PNG (always lossless). Default: 90.
    - `dpi` integer, nullable: 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.
  - `is_async` boolean: 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.

## Response `200`

Successful Response

- PhotoMockupRenderResponse: The finished photo-mockup render and where to fetch it.
  - `data` PhotoMockupRenderResult, required: Data payload in a photo mockup render response.
    - `print_files` PhotoMockupPrintFile[], required: List of rendered outputs
      - `export_path` string, required: Public URL of the rendered output
      - `duration_ms` integer, nullable: Render duration in milliseconds
      - `export_format` string, nullable: Output format used (png, jpg, webp)
    - `render_uuid` string, nullable: Identifier for this render.
  - `success` boolean: Success status

## Other responses

- `202`: Render queued (is_async=true). Poll status_url for the result, or receive a webhook on completion.

---

[API](https://skmtc.dev/sudomock/apis/sudomock-api.md) · [All operations](https://skmtc.dev/sudomock/apis/sudomock-api/llms.txt) · [OpenAPI document](https://skmtc.dev/sudomock/apis/sudomock-api/revisions/c1cc24006c60?raw)
