---
name: sudomock
description: Use when putting artwork on a product, rendering a design onto a Photoshop template's smart object, turning a product photograph into a reusable mockup, recolouring layers, editing PSD text, removing an image background, or wiring render jobs and webhooks into a store or a pipeline. Use it whenever SudoMock or a mockup API comes up.
compatibility: Needs a SudoMock API key and network access to api.sudomock.com. The same account is reachable over MCP at mcp.sudomock.com.
metadata:
  author: sudomock
  version: "1.0"
  homepage: https://sudomock.com/docs
---

# SudoMock

## Product summary

SudoMock renders artwork onto products over HTTP. There are two engines and a
request names a product, not an engine.

- **PSD mockups** are for someone who works in Photoshop. Upload a PSD or PSB
  once, and SudoMock returns the UUID of every smart object, text layer and
  group layer in it, including smart objects and text inside a smart object.
  Render that mockup again and again with different artwork,
  colours and text without uploading the file again. The template's own
  lighting, shadow and warp come through as the file authored them.
- **Photo mockups** are for someone who does not. Supply one photograph of the
  product and SudoMock turns it into a reusable mockup with print areas you can
  render onto.

Base URL `https://api.sudomock.com`. Authentication is the `x-api-key` header.
One call returns one finished image.

## When to use

Reach for this skill when the task is to:

- Put a design on a product image, by API or from an agent
- Upload a PSD or PSB and keep it as a reusable template
- Render the same template with new artwork, colours or text
- Turn a product photograph into a mockup and render onto its print areas
- Edit the text of a PSD layer without opening Photoshop
- Remove the background from an image and get a transparent PNG back
- Run renders in the background and collect them by job or by webhook
- Build mockup generation into a store, a design tool or a pipeline
- Read an error from a render and decide whether it is worth retrying

## Two ways in

Both surfaces reach the same account and spend the same credits. Pick one.

| Surface | Endpoint | Use it when |
|---------|----------|-------------|
| REST API | `https://api.sudomock.com` | You are writing code, a backend, a job runner or an integration |
| MCP server | `https://mcp.sudomock.com` | You are an agent in a client that speaks MCP and the user signs in there |

The MCP server signs the user in through their browser. Never ask for a
password, a one time code or an API key in the conversation. It publishes tools
only, no resources and no prompts, so do not ask it for any. Some tools answer
to a second, older name; use whichever the connection offers.

## Quick reference

### Authenticate a request

```bash
curl "https://api.sudomock.com/api/v1/me" \
  -H "x-api-key: sm_your_api_key"
```

Keys start with `sm_` and are created in the dashboard. The key spends credits,
so keep it on the server or in an environment variable, never in client code.
`GET /api/v1/me` is the cheapest way to confirm a key is live: it returns the
account, the plan and the remaining credits.

For a browser editor, the server creates a Studio session and the browser
receives a short lived token, so the key never leaves your infrastructure.

### Call the REST endpoints

| Operation | Purpose |
|-----------|---------|
| `POST /api/v1/psd/upload` | Upload a PSD or PSB and get its layer UUIDs |
| `GET /api/v1/psd-mockups` | List uploaded templates |
| `GET /api/v1/psd-mockups/{uuid}` | Smart objects, text layers, colours, sizes |
| `GET /api/v1/psd-mockups/{uuid}/layers` | Every layer, inside smart objects too, to hide some per render |
| `PATCH /api/v1/psd-mockups/{uuid}` | Rename a template or name its colours |
| `POST /api/v1/renders` | Render a PSD mockup |
| `POST /api/v1/renders/video` | Render a short video from a mockup |
| `POST /api/v1/photo-mockups` | Turn a product photo into a mockup |
| `PUT /api/v1/photo-mockups/{mockup_id}/print-areas` | Replace the print areas on it |
| `POST /api/v1/photo-mockups/{mockup_id}/render` | Render artwork onto it |
| `POST /api/v1/fonts` | Upload a custom TTF or OTF |
| `POST /api/v1/remove-background` | Return a transparent PNG cutout |
| `GET /api/v1/jobs/{job_id}` | Status of one background job |
| `POST /api/v1/webhook-endpoints` | Register a callback URL |
| `GET /api/v1/me` | Account, plan and remaining credits |

The full set, including delete, list, webhook delivery inspection and Studio
sessions, is in the API reference.

### Call the hosted MCP tools

Names are grouped by the job they do. Family spellings such as
`render_psd_mockup` and `render_mockup` are the same tool.

| Job | Tools |
|-----|-------|
| Look around | `get_account`, `list_psd_mockups`, `list_photo_mockups` |
| Inspect one template | `get_psd_mockup`, `get_photo_mockup` |
| Bring in a template | `upload_psd`, `create_photo_mockup`, `upload_local_file` |
| Render | `render_psd_mockup`, `render_photo_mockup`, `render_video` |
| Edit a photo mockup | `update_photo_mockup_print_areas` |
| Images | `remove_background` |
| Background work | `get_job`, `list_jobs`, `wait_for_job` |
| Callbacks | `create_webhook_endpoint`, `list_webhook_endpoints`, `update_webhook_endpoint`, `test_webhook_endpoint`, `list_webhook_deliveries`, `replay_webhook_delivery`, `rotate_webhook_secret` |
| Housekeeping | `update_psd_mockup`, `delete_psd_mockup`, `delete_photo_mockup`, `delete_webhook_endpoint` |

There is no batch render tool. One call produces one output, and several
outputs mean several calls.

### Shape a render request

```json
{
  "mockup_uuid": "MOCKUP_UUID",
  "smart_objects": [
    {
      "uuid": "SMART_OBJECT_UUID",
      "asset": { "url": "https://example.com/artwork.png", "fit": "crop" }
    }
  ],
  "text_layers": [
    { "uuid": "TEXT_LAYER_UUID", "text": "Limited edition" }
  ],
  "export_options": { "image_format": "webp", "image_size": 2048 }
}
```

`mockup_uuid` is the only required field. The response carries
`data.print_files[].export_path`, the URL of the finished image, and
`data.render_uuid`.

To leave layers out of one render, add `hidden_layers` with up to 50 layer
UUIDs from `GET /api/v1/psd-mockups/{uuid}/layers`. Hiding a group hides
everything inside it, and the template itself does not change. The list also
holds the layers inside a smart object's contents, and a layer hidden there
is hidden in every copy of that smart object. Over MCP, `get_psd_mockup` with
`include_layers` lists the same layers and `render_psd_mockup` takes the same
`hidden_layers`.

### Place artwork inside a print area

| Mode | Behaviour | Use when |
|------|-----------|----------|
| `fit` | Scales inside the area and keeps proportions. Default. | The whole design has to stay visible |
| `fill` | Stretches to the bounds and distorts proportions | The artwork already matches the proportions of the area |
| `crop` | Covers the area, keeps proportions, cuts the overflow | All over prints and whole product designs |

Colour is set per smart object with a hex value or a name you saved earlier,
and `blending_mode` selects one of the 27 layer blend modes.

### Set the output format and size

| Field | Values | Default |
|-------|--------|---------|
| `image_format` | `webp`, `png`, `jpg` | `webp` |
| `image_size` | 100 to 10000 px wide, height follows, or `original` for the PSD's own size and resolution | 2048 |
| `quality` | 1 to 100, ignored for PNG | 90 |

### Receive a result by webhook

`render.succeeded`, `render.failed`, `upload.succeeded`, `video.succeeded`,
`video.failed`, `photo_mockup.ready`, `photo_mockup.rejected`,
`photo_mockup.failed`, `photo_mockup_render.succeeded`,
`photo_mockup_render.failed`, and `webhook.test` from the test action.

A failed upload arrives as `render.failed`, so subscribe to it if you ingest
PSDs.

## Decision guidance

### PSD mockup or photo mockup

Read what is already in front of you before asking. The files in the
conversation, what the user has said about how they work, and what
`list_psd_mockups` and `list_photo_mockups` return for the account. Someone
with PSD templates and no photo mockups has already answered.

If it is still open, ask once in their own terms: is there a Photoshop file for
this product, or a photo of it? Do not guess and do not spend credits to find
out. When both lists come back empty the account is simply new.

| Situation | Engine |
|-----------|--------|
| A designer controls the template and wants smart objects, filters and text | PSD mockup |
| There is one photograph of a real product and no design file | Photo mockup |
| Several places to print on the same product | Either, both hold several areas |

### Sync or async

| Situation | Choice |
|-----------|--------|
| Someone is waiting in front of a screen | Synchronous, the default |
| Batch work, wide images, high volume | `is_async: true`, then a job or a webhook |

An async submit returns a job id. Poll `get_job`, or block on `wait_for_job`,
or take the webhook. Do not submit again because the job is queued or running.

### Artwork by URL or base64

A public HTTPS URL is simpler and the server fetches it, so the request stays
small; use it for large files. Base64 suits small artwork that is already in
memory, and it keeps artwork that is not public off the open internet. It adds
about a third to the file size, and a request must finish uploading within 100
seconds.

## Workflow

### 1. Upload a PSD once

```bash
curl -X POST "https://api.sudomock.com/api/v1/psd/upload" \
  -H "x-api-key: sm_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "psd_file_url": "https://example.com/tshirt.psd", "psd_name": "T-shirt front" }'
```

Store `data.uuid`, then the `uuid` of each smart object, text layer and group
layer. Everything after this is a render against those UUIDs.

A smart object that holds smart objects or text lists them in its own entry,
under `smart_objects` and `text_layers`, and a nested smart object can hold its
own in turn. A nested entry's `position` and `quad` are pixels in its parent
smart object's document, not on the canvas. Fill a nested slot by putting its
`uuid` in the render's `smart_objects` or `text_layers` array, like a top-level
one. Names repeat across parents, so map names to UUIDs per parent. Giving a
parent smart object an `asset` while also filling or hiding a layer inside it
returns `422` with `NESTED_SLOT_CONFLICT`.

### 2. Render it many times

```bash
curl -X POST "https://api.sudomock.com/api/v1/renders" \
  -H "x-api-key: sm_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "mockup_uuid": "MOCKUP_UUID",
    "smart_objects": [
      { "uuid": "SMART_OBJECT_UUID", "asset": { "base64": "iVBORw0KGgo...", "fit": "crop" } }
    ]
  }'
```

### 3. Turn a product photo into a mockup

Send one photograph to `POST /api/v1/photo-mockups` as `source_url` or
`source_base64`. SudoMock proposes print areas on it. Confirm them, or replace
them with `PUT /api/v1/photo-mockups/{mockup_id}/print-areas`, which takes up to eight
four point quads. Then render with `POST /api/v1/photo-mockups/{mockup_id}/render`,
naming exactly one target per entry: a print area, or the whole surface for an
all over print.

A photograph that cannot be used comes back rejected, and its credits are
returned.

### 4. Take delivery of async work

1. Register the endpoint with `POST /api/v1/webhook-endpoints`.
2. Store the returned secret. It is shown in full once, on create and on
   rotate, and later reads mask it.
3. On every delivery read `X-SudoMock-Signature` and `X-SudoMock-Timestamp`.
   The signature is `HMAC-SHA256(secret, "{timestamp}.{rawBody}")`, hex
   encoded, over the raw body.
4. Compare in constant time, reject a timestamp older than five minutes, and
   only then act on the payload.
5. Inspect attempts with
   `GET /api/v1/webhook-endpoints/{endpoint_id}/deliveries` and replay a single
   one once the endpoint is fixed.

## Common gotchas

- **Uploading the same PSD again.** Upload once, keep the mockup UUID. A second
  upload costs time and a concurrency slot for nothing.
- **Losing the webhook secret.** It is returned in full only on create and on
  rotate. Store it in the same step.
- **Verifying a signature over parsed JSON.** Use the raw request body. A
  re-serialised object produces a different hash.
- **Sending `fill` by accident.** The default `fit` never distorts. Send `fill`
  only when stretching is what you want.
- **Ignoring the concurrency headers.** `X-Concurrent-Limit`,
  `X-Concurrent-Used` and `X-Concurrent-Remaining` are on every response.
  Over the limit returns `429`. Wait for work in flight, do not retry at once.
- **Ignoring `Retry-After`.** The request rate limit is 1,000 requests per
  minute and every response carries `RateLimit-Limit`, `RateLimit-Remaining`
  and `RateLimit-Reset`. A `429` carries `Retry-After` in seconds.
- **Promising a size before checking entitlements.** A trial account renders at
  most 1024 px wide and its output carries a watermark. Above the cap the
  request returns `402` with `OUTPUT_RESOLUTION_LIMIT`.
- **Retrying a permanent error.** `LINKED_SMART_OBJECT_CONTENT_MISSING` is a
  `422` and re-uploading the same file will not help. Run Embed Linked in
  Photoshop, or supply the design in the render request.
- **Assuming a missing font.** When a text layer reports `font_available: false`
  it renders in a fallback unless you supply a font. Upload one with
  `POST /api/v1/fonts`, which takes a TTF or OTF up to 5 MB on Pro and Scale.
- **Reading REST parity into an MCP tool.** Use the schema the connection
  actually offers rather than assuming a tool mirrors its REST counterpart.

Credits are charged only on a successful request. A failed request is not
billed.

## Verification checklist

- [ ] The API key sits in an environment variable and never in client code
- [ ] `GET /api/v1/me` confirmed the key, the plan and the credits
- [ ] The mockup UUID and the layer UUIDs are stored from the upload
- [ ] Artwork is a public HTTPS URL or base64
- [ ] The fit mode is set on purpose when it is not `fit`
- [ ] The export format and width suit where the image is going
- [ ] Async submits carry `is_async` and are collected by job or webhook
- [ ] The webhook endpoint is HTTPS and reachable
- [ ] The signature is checked over the raw body, in constant time
- [ ] A timestamp older than five minutes is rejected
- [ ] Error handling branches on the error code and has a default case
- [ ] `Retry-After` and the concurrency headers are read before a retry
- [ ] Retries use exponential backoff on `429`, `500` and `502`
- [ ] The account entitlements were checked before promising a size

## Resources

- Documentation index: https://sudomock.com/docs/llms.txt
- Quickstart: https://sudomock.com/docs/quickstart
- Authentication: https://sudomock.com/docs/authentication
- Connect an agent: https://sudomock.com/docs/connect-an-agent
- Render reference: https://sudomock.com/docs/api-reference/psd-mockups/render-a-psd-mockup
- Photo mockups: https://sudomock.com/docs/photo-mockups/overview
- Webhooks: https://sudomock.com/docs/webhooks/overview
- Errors: https://sudomock.com/docs/errors
- Usage limits: https://sudomock.com/docs/api-reference/usage-limits
- Plans and credit weights: https://sudomock.com/pricing
