SudoMock
Mockups
DocsPricing
Request a demo
Get Started

Start rendering mockups in minutes

From PSD to product mockup in one API call.

Get Free API Key→Browse Templates
Public status pagePublished API pricingProduct mockup API500 one-time API credits

Site Navigation

SudoMock

Turn reusable PSD templates, artwork, and editable text into production-ready product images through REST API, no-code workflows, native storefront apps, or AI.

SudoMock is a registered DBA
1209 Mountain Rd Pl NE, Ste N
Albuquerque, NM 87110, USA

Product

  • Pricing
  • Dashboard
  • PSD Mockups
  • Changelog
  • Start Free

Developers

  • API Overview
  • MCP Server
  • Quick Start
  • Render API
  • Upload PSD
  • Authentication
  • Error Handling
  • PSD Preparation
  • Integrations

Mockups & Tools

  • All Mockups
  • Apparel Mockups
  • Drinkware Mockups
  • Wall Art Mockups
  • Home & Living
  • By Platform
  • Search Mockups
  • Background Remover
  • Free Tools

Resources

  • All Use Cases
  • T-Shirt Mockup Generator for Print on Demand
  • Tote Bag Mockup Generator for Sustainable Brands
  • Automate Mug at Scale with SudoMock
  • Blog
  • Roadmap
  • All Alternatives
  • vs Placeit
  • vs DynamicMockups
  • vs Adobe Photoshop API
  • vs Static Mockup Generators

Company

  • About
  • Contact
  • Brand Assets
  • System Status (opens in new tab)
  • Feature Requests (opens in new tab)
Blog

Latest Articles

View all →
  • 01Can You Use Mockups on Etsy? The Rule by Listing Type
  • 02Google Merchant Center Image Requirements: 500 x 500 From 2027 and Renders That Meet It
  • 03Shopify Product Image Size: 2048 px, the Real Limits and Files
  • 04Etsy Listing Photo Size: Etsy's Rules and Files That Meet Them

© 2026 SudoMock. All rights reserved.

PrivacyTermsRefundsCookies[email protected]
  1. Blog
  2. /
  3. Technical

Understanding Mockup API Data Models: A Technical Guide

In a SudoMock upload response, each smart object's uuid is the handle you send in a render request, size is the resolution to prepare artwork at, position is its box on the mockup canvas, and quad holds its four corner points. Design at size, preview with position, and the render scales your artwork into place.

Published Dec 5, 2025·Updated Oct 7, 2026·4 min read·Beck

A 3951 x 4800 design canvas labeled size, and the same print on a navy T-shirt render with its position box and quad corners

On this page

  • The De-Facto Standard: Rect + Transform
  • Anatomy of a Smart Object Response
  • size vs position: The Key Distinction
  • Working with Quad Coordinates
  • Integration Patterns
  • Working with Blend Modes
  • Next.js Integration Examples
  • Related Resources
  • Frequently asked questions

Understanding how mockup APIs structure their data is crucial for building robust integrations. This guide covers the de-facto standard data model used across the industry, what each field means, and how to use them effectively in your code.

size vs position - Visual Explanation
size
3951 x 4800
Your design canvas
4800px
3951px
Design Resolution
Upload assets at this size
→
scales to
position
507 x 620
x: 771, y: 886
Mockup Canvas
Rendered Position
Where it appears on mockup
size = Original design dimensions
position = Rendered bounds on canvas

The De-Facto Standard: Rect + Transform

Every major design tool and mockup API uses the same fundamental data model: a rectangle with position coordinates and optional transforms. This pattern comes from decades of graphics programming, from Photoshop to Canvas2D to WebGL.

x, y

Position

Top-left corner coordinates

w, h

Size

Width and height dimensions

deg

Rotation

Optional rotation angle

quad

Transform

4-point perspective

This model is universal because it's deterministic, minimal, and fast. Whether you're working with Photoshop layers, Figma frames, or mockup APIs, the core concept remains the same: define a bounding box and optionally transform it.

Anatomy of a Smart Object Response

When you upload a PSD to SudoMock, each smart object layer returns detailed metadata. Let's break down what each field means and how to use it:

JSONSmart Object Response Structure
{
"uuid": "73957ff7-82c4-4c14-947a-a6f841944d1c",
"name": "print_area",
"size": {
"width": 3951,
"height": 4800
},
"position": {
"x": 771,
"y": 886,
"width": 507,
"height": 620
},
"quad": [
[771, 886],
[1278, 886],
[1278, 1506],
[771, 1506]
],
"blend_mode": "normal",
"layer_name": "print_area"
}

Understanding Each Field

  • size (width, height): The original dimensions of the embedded smart object content. This is your design canvas size - upload assets at this resolution for best quality. The render API works in these coordinates.
  • position.x, position.y: Top-left corner placement coordinates on the mockup canvas. Useful for client-side canvas preview overlays.
  • position.width, position.height: Display dimensions after transforms. Primary use: drawing design previews on thumbnail images in browser. Not used in render API requests.
  • quad (4 points): Pre-calculated corner coordinates for perspective rendering. Useful for canvas-based rendering or custom transform implementations.
  • blend_mode: How this layer blends with layers below. Important for color overlays (multiply) or special effects (screen, overlay).

size vs position: The Key Distinction

The most important concept to understand is the difference between size and position. They represent two different things:

FieldRepresentsUse Case
size.widthEmbedded content width (3951px)Render API coordinates, design canvas
size.heightEmbedded content height (4800px)Render API coordinates, design canvas
position.xLeft edge on mockup (771px)Client-side canvas preview
position.yTop edge on mockup (886px)Client-side canvas preview
position.widthDisplay width (507px)Thumbnail overlay drawing
position.heightDisplay height (620px)Thumbnail overlay drawing

Think of it this way

size = "Upload your design at this resolution, send coordinates in render API"
position = "Use this for drawing previews on thumbnail images in browser"

In the example above, a 3951x4800 design gets scaled down to 507x620 when rendered on the mockup canvas. The scale factor is approximately 0.128x (507/3951).

Working with Quad Coordinates

The quad array contains four [x, y] coordinate pairs representing the corners of the smart object's bounding box. This is especially useful for:

  • Canvas rendering: Draw directly using canvas 2D context with precise coordinates
  • Perspective transforms: Handle non-rectangular smart objects (skewed, rotated)
  • Hit testing: Determine if a point is inside the smart object area
  • Custom overlays: Position UI elements or annotations accurately
JavaScriptUsing quad coordinates in JavaScript
// Draw smart object bounds on canvas
function drawSmartObjectBounds(ctx, smartObject) {
if (!smartObject.quad) return; // quad can be null
const [topLeft, topRight, bottomRight, bottomLeft] = smartObject.quad;
ctx.beginPath();
ctx.moveTo(topLeft[0], topLeft[1]);
ctx.lineTo(topRight[0], topRight[1]);
ctx.lineTo(bottomRight[0], bottomRight[1]);
ctx.lineTo(bottomLeft[0], bottomLeft[1]);
ctx.closePath();
ctx.strokeStyle = '#00ff00';
ctx.stroke();
}
// Check if a point is inside the smart object
function isPointInQuad(point, quad) {
const [tl, tr, br, bl] = quad;
// Simple bounding box check (for rectangular quads)
return point.x >= tl[0] && point.x <= tr[0] &&
point.y >= tl[1] && point.y <= bl[1];
}

Integration Patterns

Integration Flow
  1. 1
    Upload PSD
    /psd/upload
    →
  2. 2
    Get Metadata
    size, position, quad
    →
  3. 3
    Render
    /renders
    →
  4. 4
    Result
    WebP/PNG URL

Pattern 1: Basic Render Request

The most common pattern is uploading a PSD, storing the smart object metadata, then using it to render variations:

JavaScriptComplete integration flow
// Step 1: Upload PSD and store metadata
const uploadResponse = await fetch('https://api.sudomock.com/api/v1/psd/upload', {
method: 'POST',
headers: {
'X-API-KEY': API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({
psd_file_url: 'https://storage.example.com/tshirt-mockup.psd',
psd_name: 'T-Shirt Front'
})
});
const { data: mockup } = await uploadResponse.json();
// Store the mockup metadata for later use
const mockupId = mockup.uuid;
const smartObjects = mockup.smart_objects;
// Find the main design area
const designArea = smartObjects.find(so => so.name === 'print_area');
console.log('Design canvas size:', designArea.size); // { width: 3951, height: 4800 }
console.log('Rendered position:', designArea.position); // { x: 771, y: 886, width: 507, height: 620 }
// Step 2: Render with a design
const renderResponse = await fetch('https://api.sudomock.com/api/v1/renders', {
method: 'POST',
headers: {
'X-API-KEY': API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({
mockup_uuid: mockupId,
smart_objects: [{
uuid: designArea.uuid,
asset: {
url: 'https://storage.example.com/my-design.png',
fit: 'cover' // cover, contain, or fill
}
}],
export_options: {
image_format: 'webp',
image_size: 1024,
quality: 95
}
})
});
const { data: render } = await renderResponse.json();
console.log('Rendered mockup:', render.print_files[0].export_path);

Pattern 2: Using Position Data for Custom Rendering

If you're building a custom preview or need to render locally, the position data tells you exactly where to place the design:

JavaScriptCustom canvas preview
async function createPreview(mockupImage, designImage, smartObject) {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// Set canvas to mockup dimensions
canvas.width = mockupImage.width;
canvas.height = mockupImage.height;
// Draw the mockup background
ctx.drawImage(mockupImage, 0, 0);
// Get position data from API response
const { x, y, width, height } = smartObject.position;
// Draw the design at the correct position and size
ctx.drawImage(designImage, x, y, width, height);
return canvas.toDataURL('image/png');
}
// Usage
const preview = await createPreview(
await loadImage(mockupThumbnail),
await loadImage(myDesign),
designArea
);

Design Resolution

For best quality, prepare your design at the size dimensions (e.g., 3951x4800), not the position dimensions. The API handles scaling automatically.

Working with Blend Modes

The blend_mode field indicates how the smart object layer blends with layers below it in the PSD. Common modes include:

Blend ModeEffectCommon Use
NORMALStandard opacity blendingRegular design placement
MULTIPLYDarkens, whites become transparentColor overlays, fabric textures
SCREENLightens, blacks become transparentLight effects, glows
OVERLAYCombines multiply and screenContrast enhancement

For color smart objects (used to change product colors), MULTIPLY is typically used so the design texture shows through the color overlay. This is common in drinkware mockups and apparel templates.

Next.js Integration Examples

Here are practical examples for integrating SudoMock into your Next.js application. You can use any template from SudoMock's mockup library as a starting point. These examples show how to use the smart object metadata in real frontend code.

SudoMock Client Utility

First, create a reusable client for making API calls to SudoMock:

TypeScriptlib/sudomock.ts
// SudoMock API Client for Next.js
// Store your API key in .env.local as SUDOMOCK_API_KEY
const API_KEY = process.env.SUDOMOCK_API_KEY!
const BASE_URL = 'https://api.sudomock.com/api/v1'
export interface SmartObject {
uuid: string
name: string
size: { width: number; height: number }
position: { x: number; y: number; width: number; height: number }
quad: [number, number][] | null
blend_mode: string
}
export interface MockupData {
uuid: string
name: string
thumbnail: string
width?: number // Original PSD width
height?: number // Original PSD height
smart_objects: SmartObject[]
}
// Upload a PSD and get smart object metadata
export async function uploadPsd(psdUrl: string, name: string): Promise<MockupData> {
const response = await fetch(`${BASE_URL}/psd/upload`, {
method: 'POST',
headers: {
'X-API-KEY': API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
psd_file_url: psdUrl,
psd_name: name,
}),
})
const data = await response.json()
if (!data.success) throw new Error(data.detail)
return data.data
}
// Render a mockup with a design
export async function renderMockup(
mockupId: string,
smartObjectId: string,
designUrl: string
): Promise<string> {
const response = await fetch(`${BASE_URL}/renders`, {
method: 'POST',
headers: {
'X-API-KEY': API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
mockup_uuid: mockupId,
smart_objects: [{
uuid: smartObjectId,
asset: { url: designUrl, fit: 'cover' }
}],
export_options: {
image_format: 'webp',
image_size: 1024,
quality: 95
}
}),
})
const data = await response.json()
if (!data.success) throw new Error(data.detail)
return data.data.print_files[0].export_path
}

React Hook for Managing Mockups

A custom hook that manages mockup state and provides useful computed values from the smart object metadata:

TypeScripthooks/useMockupEditor.ts
export function useMockupEditor(initialMockup?: MockupData) {
const [mockup, setMockup] = useState<MockupData | null>(initialMockup ?? null)
const [selectedDesign, setSelectedDesign] = useState<string | null>(null)
// Find the main print area smart object
const printArea = useMemo(() => {
return mockup?.smart_objects.find(
so => so.name.toLowerCase().includes('print') ||
so.name.toLowerCase().includes('design')
)
}, [mockup])
// Calculate design requirements from size field
const designRequirements = useMemo(() => {
if (!printArea) return null
const { width, height } = printArea.size
return {
width,
height,
aspectRatio: width / height,
megapixels: (width * height) / 1000000,
recommendation: width >= 3000
? 'High resolution - perfect for print'
: 'Medium resolution - good for web'
}
}, [printArea])
// Get render position info from position field
const renderPosition = useMemo(() => {
if (!printArea) return null
const { x, y, width, height } = printArea.position
const originalSize = printArea.size
return {
x,
y,
width,
height,
scaleFactor: width / originalSize.width,
// Useful for canvas preview
bounds: { left: x, top: y, right: x + width, bottom: y + height }
}
}, [printArea])
return {
mockup,
setMockup,
printArea,
designRequirements,
renderPosition,
selectedDesign,
setSelectedDesign,
}
}

Live Preview with Canvas

Use the position data to create a real-time preview before rendering:

TypeScriptcomponents/MockupPreview.tsx
interface PreviewProps {
mockupThumbnailUrl: string
designImageUrl: string | null
// From smart_object.position in API response
position: { x: number; y: number; width: number; height: number }
}
export function MockupPreview({ mockupThumbnailUrl, designImageUrl, position }: PreviewProps) {
const canvasRef = useRef<HTMLCanvasElement>(null)
const [previewDataUrl, setPreviewDataUrl] = useState<string | null>(null)
useEffect(() => {
if (!designImageUrl || !canvasRef.current) return
const canvas = canvasRef.current
const ctx = canvas.getContext('2d')
if (!ctx) return
// Load both images
const mockupImg = new Image()
const designImg = new Image()
mockupImg.crossOrigin = 'anonymous'
designImg.crossOrigin = 'anonymous'
Promise.all([
new Promise<void>(resolve => { mockupImg.onload = () => resolve(); mockupImg.src = mockupThumbnailUrl }),
new Promise<void>(resolve => { designImg.onload = () => resolve(); designImg.src = designImageUrl }),
]).then(() => {
// Set canvas to mockup size
canvas.width = mockupImg.width
canvas.height = mockupImg.height
// Draw mockup background
ctx.drawImage(mockupImg, 0, 0)
// Draw design at the exact position from API
// The position object tells us exactly where to place it!
ctx.drawImage(
designImg,
position.x, // x coordinate from API
position.y, // y coordinate from API
position.width, // rendered width from API
position.height // rendered height from API
)
setPreviewDataUrl(canvas.toDataURL('image/png'))
})
}, [mockupThumbnailUrl, designImageUrl, position])
return (
<div className="relative aspect-square bg-slate-800 rounded-lg overflow-hidden">
<canvas ref={canvasRef} className="hidden" />
{previewDataUrl && (
<img src={previewDataUrl} alt="Preview" className="w-full h-full object-contain" />
)}
</div>
)
}

Server Action for Batch Rendering

Process multiple designs in parallel using Next.js Server Actions:

TypeScriptactions/batch-render.ts
'use server'
interface BatchResult {
designUrl: string
renderUrl: string | null
success: boolean
error?: string
}
export async function batchRenderMockups(
mockupId: string,
smartObjectId: string,
designUrls: string[]
): Promise<BatchResult[]> {
// Process 5 at a time to respect rate limits
const CONCURRENCY = 5
const results: BatchResult[] = []
for (let i = 0; i < designUrls.length; i += CONCURRENCY) {
const batch = designUrls.slice(i, i + CONCURRENCY)
const batchResults = await Promise.all(
batch.map(async (designUrl): Promise<BatchResult> => {
try {
const renderUrl = await renderMockup(mockupId, smartObjectId, designUrl)
return { designUrl, renderUrl, success: true }
} catch (error) {
return {
designUrl,
renderUrl: null,
success: false,
error: error instanceof Error ? error.message : 'Unknown error'
}
}
})
)
results.push(...batchResults)
}
return results
}

Environment Variables

Store your SudoMock API key in .env.local as SUDOMOCK_API_KEY. Never expose it in client-side code - always call SudoMock from Server Components, Server Actions, or API routes.

Plans start at $25/month. Subscriptions from $0.002 per render.

Related Resources

Upload PSD API Reference

Complete documentation for the upload endpoint

Render API Reference

All render options and parameters

Smart Objects Guide

Best practices for preparing PSD templates

Error Codes and Retries

Status codes, error codes and safe retries

Frequently asked questions

What is a mockup data model?

A mockup data model defines the structure of your mockup configuration - including Smart Object positions, layer names, transformation settings, and output parameters. It's essentially a blueprint that tells the API how to process your PSD template.

How do I identify Smart Object layers in my PSD?

Smart Object layers show a special icon in the Photoshop Layers panel. Through the API, the upload response and GET /api/v1/psd-mockups/{uuid} list every Smart Object of the template with its uuid, name and position. The uuid is what a render request sends.

Can I update multiple Smart Objects in one API call?

Yes. A render request lists several Smart Objects in its smart_objects array, each with the uuid of the Smart Object and the URL of the design to place in it. Every Smart Object in the template can take its own design in the same render.

What happens if a Smart Object uuid does not match?

The render is refused with HTTP 400 and the error code SMART_OBJECT_NOT_FOUND. The error lists the Smart Objects the template has, each with its uuid and name, so the request can be corrected. Read the uuids from the upload response or from GET /api/v1/psd-mockups/{uuid} before rendering.

How do transformations affect the inserted design?

Transformations (scale, rotation, perspective) applied to the Smart Object in Photoshop are automatically applied to any content inserted via the API. This ensures your designs appear with the same realistic warping and positioning as seen in the original template.

B

Beck

CTO

View all posts

On this page

  • The De-Facto Standard: Rect + Transform
  • Anatomy of a Smart Object Response
  • Understanding Each Field
  • size vs position: The Key Distinction
  • Working with Quad Coordinates
  • Integration Patterns
  • Pattern 1: Basic Render Request
  • Pattern 2: Using Position Data for Custom Rendering
  • Working with Blend Modes
  • Next.js Integration Examples
  • SudoMock Client Utility
  • React Hook for Managing Mockups
  • Live Preview with Canvas
  • Server Action for Batch Rendering
  • Related Resources
  • Frequently asked questions

Related articles

Flat geometric artwork in a Design_Front smart object canvas, mapped by its transform box onto a navy t-shirt render
Guide

PSD Mockup Template Guide: Best Practices for Automation

Learn how to create API-ready PSD mockup templates. Complete guide covering dimensions, Smart Object setup, layer naming, blend modes, and optimization for automation.

Dec 24, 2025 · 7 min read

One chat prompt runs list_mockups, get_mockup_details and render_mockup on mcp.sudomock.com, returning a logo t-shirt render
Technical

SudoMock Now Works with Claude, Cursor, ChatGPT, and Any MCP-Compatible AI Tool

Render product mockups directly from any AI assistant that supports MCP. Claude, Cursor, VS Code, ChatGPT, Windsurf, and more.

Mar 23, 2026 · 7 min read

Six colorways of one t-shirt PSD rendered by API, one color hex per request
Tutorial

Every T-Shirt Color Variant Mockup from One PSD by API

One PSD with a color smart object renders every t-shirt colorway: one request per color, shown with six real renders.

Oct 1, 2026 · 4 min read

Explore by use case

See SudoMock in action for your specific product category

Print on Demand Mockup Automation for POD SellersBulk Mockup Generation API for Enterprise ScaleT-Shirt Mockup Generator API for Print on DemandCanvas Print Mockup Generator for Artists & PhotographersHoodie Mockup Generator APIPoster Mockup Generator API for Wall Art Sellers

Your own PSD, rendered via API

Render your own PSD through the API. Start with 500 one-time credits, no card.

Start Free View Docs

Render your own PSD via API with 500 one-time credits.

Start Free · 500 credits, no card