Skip to main content
This page puts a rendered mockup behind a PHP route. You upload a PSD once, then every request that arrives with an artwork URL comes back with a finished image URL.

Wire SudoMock into a PHP project.

Open in Cursor

Prerequisites

  • PHP 7.4 or newer with the curl extension enabled.
  • An API key from API keys, held in the environment as SUDOMOCK_API_KEY.
  • A PSD with at least one smart object. Preparing a PSD covers what the file needs.
  • The Quickstart if you have never called the API, since this page assumes the two requests it walks through.

Guide

1

Confirm the extension and the key

PHP reaches the API over HTTPS with the curl extension, which ships enabled in most builds. Confirm it, and confirm the key answers, before you write anything.
Keys begin with sm_ and go in the x-api-key header. Keep yours in the environment so it never reaches source control.
2

Write one request helper

Both calls are the same shape, so they share one function. It reads the key, posts JSON, and hands back the status next to the decoded body.
sudomock.php
The timeout matters. A render holds the connection until the image is ready, and a default PHP timeout will cut it off before the answer lands.
3

Upload the PSD once

Run this from the command line, not from a route. It gives you two identifiers that stay valid for every render after it.
upload.php
Run it, then put the two UUIDs it prints in the environment the route will run in.
Run it
The response also lists the text layers and group layers the file holds, each with a UUID you can address the same way.
4

Render from a route

The route takes an artwork URL, calls the render endpoint, and answers with the image URL. Failures keep their status instead of collapsing into a generic error.
render.php
Serve it from the shell holding those two variables, with php -S localhost:8000, then send it an artwork.
Call it
fit decides how the artwork meets the smart object area, and Fit and blend modes shows what each value does to the result.
A failed call answers with error_code where one applies, which is why the route passes it through rather than swallowing it. One worth knowing early is OUTPUT_RESOLUTION_LIMIT: an account still on trial credits renders at most 1024 px wide, so an image_size above that answers 402 instead of quietly shrinking. Errors lists every code and says which statuses are worth a retry. For a render that takes longer than a web request should wait, add 'is_async' => true to the body. That call answers 202 with a job_id instead of an image, so widen the status check before you switch. Poll GET /api/v1/jobs/{job_id} from a worker, or let a webhook deliver the finished render to you. A product photo works the same way. Create the mockup with POST /api/v1/photo-mockups, then render it at POST /api/v1/photo-mockups/{mockup_id}/render, reusing the helper above. Creation answers 201 and the render answers 200, so widen the status check there too.

Next steps

Webhooks

Let a finished render call your PHP endpoint instead of polling it.

Photo mockups

Turn a product photo into a reusable mockup and render onto it.

Errors

Every code, every status, and which ones are worth retrying.