2D Mockups (Setup)
Place your artwork onto a product photo. Turn any apparel, poster, or packshot image into a reusable mockup, then render unlimited designs onto its print areas.
When to use this
2D is a two-step flow
How It Works
A 2D mockup is created once and reused for every design. Creating it is synchronous by default: the printable areas on your product photo are found and prepared, and the call returns the ready mockup — one call, no polling. Pass is_async: true for a queued job with webhook delivery instead. Rendering is always synchronous and returns a hosted image URL.
POST /api/v1/sudoai/2d-mockups returns the ready mockup with its print-area quads. Costs 25 credits.is_async: true, poll the job or receive a webhook first, then fetch the mockup.POST /api/v1/sudoai/2d-mockups/{mockup_uuid}/render returns a hosted image. Costs 5 credits.Create once, render forever
Authentication
Every request uses your API key in the x-api-key header. Get a key from your Dashboard.
x-api-keystringRequiredYour SudoMock API key, starting with sm_.
Content-TypestringRequiredMust be application/json for POST and PUT requests.
Idempotency-KeystringOptional. Safely retry a create request without charging twice. Max 255 characters. Reusing a key with a different body returns 409.
Create a Mockup
/api/v1/sudoai/2d-mockupsSend exactly one image source. By default the create is synchronous: the call blocks until the mockup is ready and returns it with a 201 Created — one call, no polling. Pass is_async: true to queue it instead and get a 202 Accepted job you can poll (or receive a webhook). Either way, if the image cannot be used for a mockup, the 25 credits are refunded automatically.
Request Body
source_urlstringPublic HTTPS URL of the product photo. Provide either source_url or source_base64, not both.
source_base64stringBase64-encoded product photo, with or without a data URL prefix. Provide either source_base64 or source_url, not both.
namestringOptional display name for the mockup. Max 255 characters.
is_asyncbooleanOptional, default false. When false the call returns the finished mockup (201). When true it returns immediately with a 202 job to poll (or a webhook) — useful for batch creates.
1{2 "source_url": "https://your-domain.com/product-photo.jpg",3 "name": "Classic Tee - Front"4}
Response (default, synchronous)
1{2 "data": {3 "mockup_id": "9b0a74cd-0ebb-4748-a748-976fec8cc000",4 "name": "Classic Tee - Front",5 "status": "ready",6 "thumbnail_url": "https://cdn.sudomock.com/2d-mockups/9b0a74cd.../thumb.webp",7 "source_width": 2000,8 "source_height": 2400,9 "quads": [10 {11 "print_area_id": "223e4567-e89b-12d3-a456-426614174001",12 "points": [[420, 560], [1580, 560], [1600, 1840], [400, 1840]],13 "sort_order": 014 }15 ],16 "version": 1,17 "created_at": "2026-07-20T10:00:00Z",18 "updated_at": "2026-07-20T10:00:12Z"19 },20 "success": true21}
The synchronous response is the mockup itself, including its print-area quads — you can go straight to rendering. See Track and Fetch the Mockup below for the is_async: true job flow.
Track and Fetch the Mockup
/api/v1/sudoai/2d-mockups/{mockup_uuid}You only need this when you pass is_async: true — the synchronous default already returns the mockup. For an async create, poll the job at status_url until its status becomes succeeded (or receive a webhook); the completed job carries the new mockup_uuid. See the Jobs reference for the full poll contract.
1{2 "job_id": "b7f2c1a0-9e34-4d21-8f0a-1c2b3d4e5f60",3 "kind": "2d_create",4 "status": "queued",5 "status_url": "/api/v1/jobs/b7f2c1a0-9e34-4d21-8f0a-1c2b3d4e5f60"6}
1{2 "job_id": "b7f2c1a0-9e34-4d21-8f0a-1c2b3d4e5f60",3 "kind": "2d_create",4 "status": "succeeded",5 "result_url": "/api/v1/sudoai/2d-mockups/9b0a74cd-0ebb-4748-a748-976fec8cc000",6 "mockup_uuid": "9b0a74cd-0ebb-4748-a748-976fec8cc000",7 "error": null,8 "created_at": "2026-07-20T10:00:00Z",9 "updated_at": "2026-07-20T10:00:12Z"10}
Then fetch the mockup itself to read its print areas. Each print area is a four-corner quad in image coordinates, returned in the quads array.
1{2 "data": {3 "mockup_id": "9b0a74cd-0ebb-4748-a748-976fec8cc000",4 "name": "Classic Tee - Front",5 "status": "ready",6 "thumbnail_url": "https://cdn.sudomock.com/2d-mockups/9b0a74cd.../thumb.webp",7 "source_width": 2000,8 "source_height": 2400,9 "quads": [10 {11 "print_area_id": "223e4567-e89b-12d3-a456-426614174001",12 "points": [[420, 560], [1580, 560], [1600, 1840], [400, 1840]],13 "sort_order": 014 }15 ],16 "version": 1,17 "created_at": "2026-07-20T10:00:00Z",18 "updated_at": "2026-07-20T10:00:12Z"19 },20 "success": true21}
Mockup Fields
data.mockup_idstringRequiredUUID of the mockup. Pass it in the render URL path.
data.namestringRequiredDisplay name of the mockup.
data.statusstringRequiredMockup state: draft, processing, ready, or error. Print areas are usable once ready.
data.thumbnail_urlstringPreview thumbnail URL.
data.source_widthintegerSource photo width in pixels. Print-area points are in this coordinate space.
data.source_heightintegerSource photo height in pixels.
data.quadsarrayRequiredPrint areas detected on the photo. Each entry has print_area_id, points, and sort_order.
data.quads[].print_area_idstringRequiredUUID of the print area. Pass this as uuid inside the render print_areas array.
data.quads[].pointsarrayRequiredFour [x, y] corner points, ordered top-left, top-right, bottom-right, bottom-left.
data.quads[].sort_orderintegerRequiredDisplay order of the print area, starting at 0.
Set Print Areas (Optional)
/api/v1/sudoai/2d-mockups/{mockup_uuid}/print-areasThe print areas prepared at creation work out of the box. Use this endpoint only when you want to override them with your own placement. It replaces all print areas in the order you send, so include every area you want to keep. Available once the mockup is ready.
Prefer to place them visually? A Studio 2d-setup session opens a setup toolbar where you refine the product area, draw the print areas, and preview placement before saving. See Setting up print areas.
Request Body
print_areasarrayRequiredOne to eight print areas. Array order becomes the sort order.
print_areas[].pointsarrayRequiredExactly four [x, y] corner points, in image coordinates, ordered top-left, top-right, bottom-right, bottom-left. Each area must be a convex four-point shape inside the source image.
1{2 "print_areas": [3 {4 "points": [[420, 560], [1580, 560], [1600, 1840], [400, 1840]]5 }6 ]7}
1{2 "data": {3 "mockup_id": "9b0a74cd-0ebb-4748-a748-976fec8cc000",4 "print_areas": [5 {6 "print_area_id": "223e4567-e89b-12d3-a456-426614174001",7 "points": [[420, 560], [1580, 560], [1600, 1840], [400, 1840]],8 "sort_order": 09 }10 ]11 },12 "success": true13}
Render Artwork
/api/v1/sudoai/2d-mockups/{mockup_uuid}/renderRender one or more designs onto a mockup you created earlier. Each print area takes an artwork image, a solid color, or both. The response returns a hosted image URL. This call is synchronous.
Request Body
mockup_uuidstringRequiredPath parameter in the URL, not the body: UUID of the 2D mockup to render, from the create job or the get-mockup response.
print_areasarrayRequiredOne to eight print-area configurations. Each is matched to the mockup by its uuid.
export_optionsobjectOutput format, size, and quality. Optional; sensible defaults apply.
Print Area Configuration
Artwork or color required
artwork_url (or base64) or a color. You can supply both to tint the artwork.uuidstringRequiredThe print_area_id from the get-mockup response, identifying which area to fill.
artwork_urlstringURL of the artwork image to place. Provide artwork_url or base64.
base64stringBase64-encoded artwork image. Skips the download step. Provide base64 or artwork_url.
colorstringSolid color overlay in #RRGGBB format (e.g. '#FF0000'). Can be used alone or to tint the artwork.
adjustmentsobjectPer-artwork image adjustments. See Adjustments below.
placementobjectHow the artwork sits inside the print area. See Placement below.
Adjustments
brightnessinteger= 0Brightness (-150 to 150). 0 = no change.
contrastinteger= 0Contrast (-100 to 100). 0 = no change.
saturationinteger= 0Saturation (-100 to 100). -100 = grayscale.
vibranceinteger= 0Vibrance (-100 to 100). Boosts muted tones while protecting skin tones.
opacityinteger= 100Artwork opacity (0 to 100). 0 = transparent, 100 = opaque.
blurinteger= 0Gaussian blur (0 to 100). 0 = sharp.
blend_modestring= multiplyHow the artwork blends with the product surface. 'multiply' keeps the fabric or material texture visible; 'normal' lays the artwork flat.
warp_strengthnumber= 1.5How strongly the artwork follows the product's surface curves (0 to 2). 0 disables it.
edge_expandinteger= 0Fills thin gaps at the artwork border (0 to 50). 0 disables it.
texture_strengthinteger= 0How strongly the artwork picks up the product surface texture (0 to 100). 0 disables it.
Placement
positionenum= centerAnchor within the print area: center, top_left, top_center, top_right, center_left, center_right, bottom_left, bottom_center, bottom_right.
coverageinteger= 70Percent of the print area the artwork covers (10 to 100). Ignored when scale is set.
fitenum= containHow the artwork fits its box: 'contain' fits inside preserving aspect ratio, 'fill' stretches to the bounds, 'cover' fills and crops excess.
scalenumberScale multiplier for the artwork (0.01 to 10). Overrides coverage and fit sizing.
rotationnumber= 0Rotation in degrees, clockwise positive.
offset_xinteger= 0Horizontal pixel offset from the anchor position.
offset_yinteger= 0Vertical pixel offset from the anchor position.
Export Options
image_formatenum= webpOutput format: webp (30-70% smaller, recommended), png (lossless, quality ignored), or jpg (smallest, no transparency).
image_sizeinteger= 2048Output width in pixels (100 to 10000). Height is derived from the source aspect ratio. Powers of two (1024, 2048, 4096) are recommended.
qualityinteger= 90Compression quality for JPG and WebP (1 to 100). Ignored for PNG.
dpiinteger= nullPrint resolution tag written into the file metadata (72 to 2400). Metadata only; image_size controls the real pixels. For a print file, size image_size = print_inches x dpi.
1{2 "print_areas": [3 {4 "uuid": "223e4567-e89b-12d3-a456-426614174001",5 "artwork_url": "https://your-domain.com/design.png",6 "adjustments": {7 "blend_mode": "multiply",8 "opacity": 959 },10 "placement": {11 "position": "center",12 "coverage": 80,13 "fit": "contain"14 }15 }16 ],17 "export_options": {18 "image_format": "png",19 "image_size": 2048,20 "quality": 9521 }22}
Response
1{2 "data": {3 "render_uuid": "9adcc828-1f4e-4a2b-9c3d-2e6f8b0a1d77",4 "print_files": [5 {6 "export_path": "https://cdn.sudomock.com/renders/2d/9b0a74cd.../render.png",7 "duration_ms": 1180,8 "export_format": "png"9 }10 ]11 },12 "success": true13}
data.render_uuidstringIdentifier for this render.
data.print_filesarrayRequiredRendered output files.
data.print_files[].export_pathstringRequiredHosted URL of the rendered image.
data.print_files[].duration_msintegerRender duration in milliseconds.
data.print_files[].export_formatstringOutput format used (png, jpg, or webp).
No watermark
Prefer no backend? Embed Studio
Security
Code Examples
1# 1. Create a reusable 2D mockup (synchronous: the call returns the ready mockup)2curl -X POST "https://api.sudomock.com/api/v1/sudoai/2d-mockups" \3 -H "Content-Type: application/json" \4 -H "x-api-key: sm_your_api_key" \5 -d '{6 "source_url": "https://your-domain.com/product-photo.jpg",7 "name": "Classic Tee - Front"8 }'9# -> 201 { "data": { "mockup_id": "...", "quads": [{ "print_area_id": "...", ... }] } }10# Add "is_async": true to get a 202 { "job_id", "status_url" } job to poll instead.1112# 2. Render your artwork onto a print area13curl -X POST "https://api.sudomock.com/api/v1/sudoai/2d-mockups/MOCKUP_UUID/render" \14 -H "Content-Type: application/json" \15 -H "x-api-key: sm_your_api_key" \16 -d '{17 "print_areas": [{18 "uuid": "PRINT_AREA_ID",19 "artwork_url": "https://your-domain.com/design.png",20 "placement": { "position": "center", "coverage": 80 }21 }],22 "export_options": { "image_format": "png", "image_size": 2048 }23 }'
Webhooks
Instead of polling, configure a webhook endpoint to be notified when a creation job finishes. Set it up and verify signatures on the Webhooks page. The 2D creation flow emits these events:
2d_mockup.readyeventThe mockup was created and its print areas are ready to render.
2d_mockup.rejectedeventThe image was not suitable for a mockup. The payload includes a reason. Credits are refunded.
2d_mockup.failedeventThe creation job failed unexpectedly. Credits are refunded.
1{2 "mockup_id": "9b0a74cd-0ebb-4748-a748-976fec8cc000",3 "name": "Classic Tee - Front",4 "status": "ready",5 "print_areas": [6 {7 "print_area_id": "223e4567-e89b-12d3-a456-426614174001",8 "points": [[420, 560], [1580, 560], [1600, 1840], [400, 1840]],9 "sort_order": 010 }11 ]12}
Idempotent by design
mockup_id and the event name so a repeated delivery is a safe no-op.Error Responses
Invalid input, such as both or neither image source on create, or a print area outside the source image.
1{2 "error_code": "INVALID_SOURCE",3 "message": "Provide exactly one of source_url or source_base64.",4 "detail": "Remove one source field, or add the missing source field.",5 "success": false6}
Missing or invalid API key.
1{2 "detail": "Not authenticated",3 "success": false4}
Not enough credits. Create needs 25 credits, render needs 5. The response includes actionable links and the credit reset time.
1{2 "error": "credits_exhausted",3 "message": "You've run out of credits for this billing period.",4 "actions": [5 { "label": "Enable Pay-As-You-Go", "url": "https://sudomock.com/dashboard/billing?action=enable-payg" },6 { "label": "Upgrade Plan", "url": "https://sudomock.com/pricing" }7 ],8 "credits_reset_at": "2026-08-01T00:00:00Z"9}
The mockup UUID does not exist or is not owned by your account.
1{2 "detail": "Failed to retrieve mockup",3 "success": false4}
Print areas can only be changed after the mockup is ready, or an Idempotency-Key was reused with a different request body.
1{2 "error_code": "MOCKUP_NOT_SETTABLE",3 "message": "Print areas can only be changed after the mockup is ready.",4 "suggestion": "Wait for the creation job to finish and try again."5}
Rate limit or concurrent render limit exceeded. Retry after the indicated delay.
1{2 "detail": "Rate limit exceeded. Try again in 30 seconds.",3 "error": {4 "type": "rate_limit_exceeded",5 "code": "RATE_LIMIT_EXCEEDED",6 "retry_after": 30,7 "resource": "api"8 }9}